summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Marko <peter.marko@siemens.com>2025-02-17 21:34:25 +0100
committerSteve Sakoman <steve@sakoman.com>2025-02-21 06:25:05 -0800
commit14da16b41c362c827ad17049642fbadb39ef2599 (patch)
treee0f414059220c9749dfe6119160ee18982502f6d
parenta09597e192a4d722a68898f2c9d2f0934b1a9fae (diff)
downloadpoky-14da16b41c362c827ad17049642fbadb39ef2599.tar.gz
gnutls: patch CVE-2024-12243
Backport following patch to address this CVE: https://gitlab.com/gnutls/gnutls/-/commit/4760bc63531e3f5039e70ede91a20e1194410892 (From OE-Core rev: e5316a9019e6b9ad5a66b6070ea863705a26c633) Signed-off-by: Peter Marko <peter.marko@siemens.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
-rw-r--r--meta/recipes-support/gnutls/gnutls/CVE-2024-12243.patch1149
-rw-r--r--meta/recipes-support/gnutls/gnutls_3.8.4.bb1
2 files changed, 1150 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..a7af87718f
--- /dev/null
+++ b/meta/recipes-support/gnutls/gnutls/CVE-2024-12243.patch
@@ -0,0 +1,1149 @@
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
14Upstream-Status: Backport [https://gitlab.com/gnutls/gnutls/-/commit/4760bc63531e3f5039e70ede91a20e1194410892]
15Signed-off-by: Peter Marko <peter.marko@siemens.com>
16---
17 lib/datum.c | 7 +-
18 lib/x509/name_constraints.c | 595 +++++++++++++++++++++---------------
19 lib/x509/x509_ext.c | 80 +++--
20 lib/x509/x509_ext_int.h | 5 +
21 lib/x509/x509_int.h | 21 +-
22 5 files changed, 399 insertions(+), 309 deletions(-)
23
24diff --git a/lib/datum.c b/lib/datum.c
25index 66e016965..5577c2b4a 100644
26--- a/lib/datum.c
27+++ b/lib/datum.c
28@@ -29,6 +29,7 @@
29 #include "num.h"
30 #include "datum.h"
31 #include "errors.h"
32+#include "intprops.h"
33
34 /* On error, @dat is not changed. */
35 int _gnutls_set_datum(gnutls_datum_t *dat, const void *data, size_t data_size)
36@@ -60,7 +61,11 @@ int _gnutls_set_strdatum(gnutls_datum_t *dat, const void *data,
37 if (data == NULL)
38 return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
39
40- unsigned char *m = gnutls_malloc(data_size + 1);
41+ size_t capacity;
42+ if (!INT_ADD_OK(data_size, 1, &capacity))
43+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
44+
45+ unsigned char *m = gnutls_malloc(capacity);
46 if (!m)
47 return GNUTLS_E_MEMORY_ERROR;
48
49diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c
50index 8327a9d94..3c6e30630 100644
51--- a/lib/x509/name_constraints.c
52+++ b/lib/x509/name_constraints.c
53@@ -33,51 +33,98 @@
54 #include <gnutls/x509-ext.h>
55 #include "x509_b64.h"
56 #include "x509_int.h"
57+#include "x509_ext_int.h"
58 #include <libtasn1.h>
59
60 #include "ip.h"
61 #include "ip-in-cidr.h"
62+#include "intprops.h"
63+
64+#define MAX_NC_CHECKS (1 << 20)
65+
66+struct name_constraints_node_st {
67+ unsigned type;
68+ gnutls_datum_t name;
69+};
70+
71+struct name_constraints_node_list_st {
72+ struct name_constraints_node_st **data;
73+ size_t size;
74+ size_t capacity;
75+};
76+
77+struct gnutls_name_constraints_st {
78+ struct name_constraints_node_list_st nodes; /* owns elements */
79+ struct name_constraints_node_list_st permitted; /* borrows elements */
80+ struct name_constraints_node_list_st excluded; /* borrows elements */
81+};
82+
83+static struct name_constraints_node_st *
84+name_constraints_node_new(gnutls_x509_name_constraints_t nc, unsigned type,
85+ unsigned char *data, unsigned int size);
86+
87+static int
88+name_constraints_node_list_add(struct name_constraints_node_list_st *list,
89+ struct name_constraints_node_st *node)
90+{
91+ if (!list->capacity || list->size == list->capacity) {
92+ size_t new_capacity = list->capacity;
93+ struct name_constraints_node_st **new_data;
94+
95+ if (!INT_MULTIPLY_OK(new_capacity, 2, &new_capacity) ||
96+ !INT_ADD_OK(new_capacity, 1, &new_capacity))
97+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
98+ new_data = _gnutls_reallocarray(
99+ list->data, new_capacity,
100+ sizeof(struct name_constraints_node_st *));
101+ if (!new_data)
102+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
103+ list->capacity = new_capacity;
104+ list->data = new_data;
105+ }
106+ list->data[list->size++] = node;
107+ return 0;
108+}
109
110 // for documentation see the implementation
111-static int
112-name_constraints_intersect_nodes(name_constraints_node_st *nc1,
113- name_constraints_node_st *nc2,
114- name_constraints_node_st **intersection);
115+static int name_constraints_intersect_nodes(
116+ gnutls_x509_name_constraints_t nc,
117+ const struct name_constraints_node_st *node1,
118+ const struct name_constraints_node_st *node2,
119+ struct name_constraints_node_st **intersection);
120
121 /*-
122- * is_nc_empty:
123+ * _gnutls_x509_name_constraints_is_empty:
124 * @nc: name constraints structure
125- * @type: type (gnutls_x509_subject_alt_name_t)
126+ * @type: type (gnutls_x509_subject_alt_name_t or 0)
127 *
128 * Test whether given name constraints structure has any constraints (permitted
129 * or excluded) of a given type. @nc must be allocated (not NULL) before the call.
130+ * If @type is 0, type checking will be skipped.
131 *
132- * Returns: 0 if @nc contains constraints of type @type, 1 otherwise
133+ * Returns: false if @nc contains constraints of type @type, true otherwise
134 -*/
135-static unsigned is_nc_empty(struct gnutls_name_constraints_st *nc,
136- 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 /* no constraint for that type exists */
170- return 1;
171+ return true;
172 }
173
174 /*-
175@@ -115,21 +162,16 @@ static int validate_name_constraints_node(gnutls_x509_subject_alt_name_t type,
176 return GNUTLS_E_SUCCESS;
177 }
178
179-int _gnutls_extract_name_constraints(asn1_node c2, const char *vstr,
180- name_constraints_node_st **_nc)
181+static int extract_name_constraints(gnutls_x509_name_constraints_t nc,
182+ asn1_node c2, const char *vstr,
183+ struct name_constraints_node_list_st *nodes)
184 {
185 int ret;
186 char tmpstr[128];
187 unsigned indx;
188 gnutls_datum_t tmp = { NULL, 0 };
189 unsigned int type;
190- struct name_constraints_node_st *nc, *prev;
191-
192- prev = *_nc;
193- if (prev != NULL) {
194- while (prev->next != NULL)
195- prev = prev->next;
196- }
197+ struct name_constraints_node_st *node;
198
199 for (indx = 1;; indx++) {
200 snprintf(tmpstr, sizeof(tmpstr), "%s.?%u.base", vstr, indx);
201@@ -172,25 +214,19 @@ int _gnutls_extract_name_constraints(asn1_node c2, const char *vstr,
202 goto cleanup;
203 }
204
205- nc = gnutls_malloc(sizeof(struct name_constraints_node_st));
206- if (nc == NULL) {
207+ node = name_constraints_node_new(nc, type, tmp.data, tmp.size);
208+ _gnutls_free_datum(&tmp);
209+ if (node == NULL) {
210 gnutls_assert();
211 ret = GNUTLS_E_MEMORY_ERROR;
212 goto cleanup;
213 }
214
215- memcpy(&nc->name, &tmp, sizeof(gnutls_datum_t));
216- nc->type = type;
217- nc->next = NULL;
218-
219- if (prev == NULL) {
220- *_nc = prev = nc;
221- } else {
222- prev->next = nc;
223- prev = nc;
224+ ret = name_constraints_node_list_add(nodes, node);
225+ if (ret < 0) {
226+ gnutls_assert();
227+ goto cleanup;
228 }
229-
230- tmp.data = NULL;
231 }
232
233 assert(ret < 0);
234@@ -205,84 +241,104 @@ cleanup:
235 return ret;
236 }
237
238+int _gnutls_x509_name_constraints_extract(asn1_node c2,
239+ const char *permitted_name,
240+ const char *excluded_name,
241+ gnutls_x509_name_constraints_t nc)
242+{
243+ int ret;
244+
245+ ret = extract_name_constraints(nc, c2, permitted_name, &nc->permitted);
246+ if (ret < 0)
247+ return gnutls_assert_val(ret);
248+ ret = extract_name_constraints(nc, c2, excluded_name, &nc->excluded);
249+ if (ret < 0)
250+ return gnutls_assert_val(ret);
251+
252+ return ret;
253+}
254+
255 /*-
256- * _gnutls_name_constraints_node_free:
257+ * name_constraints_node_free:
258 * @node: name constraints node
259 *
260- * Deallocate a list of name constraints nodes starting at the given node.
261+ * Deallocate a name constraints node.
262 -*/
263-void _gnutls_name_constraints_node_free(name_constraints_node_st *node)
264+static void name_constraints_node_free(struct name_constraints_node_st *node)
265 {
266- name_constraints_node_st *next, *t;
267-
268- t = node;
269- while (t != NULL) {
270- next = t->next;
271- gnutls_free(t->name.data);
272- gnutls_free(t);
273- t = next;
274+ if (node) {
275+ gnutls_free(node->name.data);
276+ gnutls_free(node);
277 }
278 }
279
280 /*-
281 * name_constraints_node_new:
282 * @type: name constraints type to set (gnutls_x509_subject_alt_name_t)
283+ * @nc: a %gnutls_x509_name_constraints_t
284 * @data: name.data to set or NULL
285 * @size: name.size to set
286 *
287 * Allocate a new name constraints node and set its type, name size and name data.
288- * If @data is set to NULL, name data will be an array of \x00 (the length of @size).
289- * The .next pointer is set to NULL.
290 *
291 * Returns: Pointer to newly allocated node or NULL in case of memory error.
292 -*/
293-static name_constraints_node_st *
294-name_constraints_node_new(unsigned type, unsigned char *data, unsigned int size)
295+static struct name_constraints_node_st *
296+name_constraints_node_new(gnutls_x509_name_constraints_t nc, unsigned type,
297+ unsigned char *data, unsigned int size)
298 {
299- name_constraints_node_st *tmp =
300- gnutls_malloc(sizeof(struct name_constraints_node_st));
301+ struct name_constraints_node_st *tmp;
302+ int ret;
303+
304+ tmp = gnutls_calloc(1, sizeof(struct name_constraints_node_st));
305 if (tmp == NULL)
306 return NULL;
307 tmp->type = type;
308- tmp->next = NULL;
309- tmp->name.size = size;
310- tmp->name.data = NULL;
311- if (tmp->name.size > 0) {
312- tmp->name.data = gnutls_malloc(tmp->name.size);
313- if (tmp->name.data == NULL) {
314+
315+ if (data) {
316+ ret = _gnutls_set_strdatum(&tmp->name, data, size);
317+ if (ret < 0) {
318+ gnutls_assert();
319 gnutls_free(tmp);
320 return NULL;
321 }
322- if (data != NULL) {
323- memcpy(tmp->name.data, data, size);
324- } else {
325- memset(tmp->name.data, 0, size);
326- }
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 int
361-_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,
371- *prev = NULL;
372+ struct name_constraints_node_st *tmp;
373 int ret, type, used;
374+ struct name_constraints_node_list_st removed = { .data = NULL,
375+ .size = 0,
376+ .capacity = 0 };
377
378 /* temporary array to see, if we need to add universal excluded constraints
379 * (see phase 3 for details)
380@@ -291,61 +347,73 @@ _gnutls_name_constraints_intersect(name_constraints_node_st **_nc,
381 memset(types_with_empty_intersection, 0,
382 sizeof(types_with_empty_intersection));
383
384- if (*_nc == NULL || _nc2 == NULL)
385+ if (permitted->size == 0 || permitted2->size == 0)
386 return 0;
387
388 /* Phase 1
389- * For each name in _NC, if a _NC2 does not contain a name
390- * with the same type, preserve the original name.
391- * Do this also for node of unknown type (not DNS, email, IP */
392- t = nc = *_nc;
393- while (t != NULL) {
394- name_constraints_node_st *next = t->next;
395- nc2 = _nc2;
396- while (nc2 != NULL) {
397- if (t->type == nc2->type) {
398+ * For each name in PERMITTED, if a PERMITTED2 does not contain a name
399+ * with the same type, move the original name to REMOVED.
400+ * Do this also for node of unknown type (not DNS, email, IP) */
401+ for (size_t i = 0; i < permitted->size;) {
402+ struct name_constraints_node_st *t = permitted->data[i];
403+ const struct name_constraints_node_st *found = NULL;
404+
405+ for (size_t j = 0; j < permitted2->size; j++) {
406+ const struct name_constraints_node_st *t2 =
407+ permitted2->data[j];
408+ if (t->type == t2->type) {
409 // check bounds (we will use 't->type' as index)
410- if (t->type > GNUTLS_SAN_MAX || t->type == 0)
411- return gnutls_assert_val(
412- GNUTLS_E_INTERNAL_ERROR);
413+ if (t->type > GNUTLS_SAN_MAX || t->type == 0) {
414+ gnutls_assert();
415+ ret = GNUTLS_E_INTERNAL_ERROR;
416+ goto cleanup;
417+ }
418 // note the possibility of empty intersection for this type
419 // if we add something to the intersection in phase 2,
420 // we will reset this flag back to 0 then
421 types_with_empty_intersection[t->type - 1] = 1;
422+ found = t2;
423 break;
424 }
425- nc2 = nc2->next;
426 }
427- if (nc2 == NULL || (t->type != GNUTLS_SAN_DNSNAME &&
428- t->type != GNUTLS_SAN_RFC822NAME &&
429- t->type != GNUTLS_SAN_IPADDRESS)) {
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+
440+ if (found != NULL && (t->type == GNUTLS_SAN_DNSNAME ||
441+ t->type == GNUTLS_SAN_RFC822NAME ||
442+ t->type == GNUTLS_SAN_IPADDRESS)) {
443+ /* move node from PERMITTED to REMOVED */
444+ ret = name_constraints_node_list_add(&removed, t);
445+ if (ret < 0) {
446+ gnutls_assert();
447+ goto cleanup;
448+ }
449+ /* remove node by swapping */
450+ if (i < permitted->size - 1)
451+ permitted->data[i] =
452+ permitted->data[permitted->size - 1];
453+ permitted->size--;
454+ continue;
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)
482- return gnutls_assert_val(ret);
483+ ret = name_constraints_intersect_nodes(nc, t, t2, &tmp);
484+ if (ret < 0) {
485+ gnutls_assert();
486+ goto cleanup;
487+ }
488 used = 1;
489 // if intersection is not empty
490 if (tmp !=
491@@ -360,32 +428,34 @@ _gnutls_name_constraints_intersect(name_constraints_node_st **_nc,
492 // we will not add universal excluded constraint for this type
493 types_with_empty_intersection[tmp->type - 1] =
494 0;
495- // add intersection node to DEST
496- tmp->next = dest;
497- dest = tmp;
498+ // add intersection node to PERMITTED
499+ ret = name_constraints_node_list_add(permitted,
500+ tmp);
501+ if (ret < 0) {
502+ gnutls_assert();
503+ goto cleanup;
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(
514- nc2->type, nc2->name.data, nc2->name.size);
515+ nc, t2->type, t2->name.data, t2->name.size);
516 if (tmp == NULL) {
517- _gnutls_name_constraints_node_free(dest);
518- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
519+ gnutls_assert();
520+ ret = GNUTLS_E_MEMORY_ERROR;
521+ goto cleanup;
522+ }
523+ ret = name_constraints_node_list_add(permitted, tmp);
524+ if (ret < 0) {
525+ gnutls_assert();
526+ goto cleanup;
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@@ -400,63 +470,77 @@ _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,
546- NULL, 8);
547+ tmp = name_constraints_node_new(
548+ nc, GNUTLS_SAN_IPADDRESS, NULL, 8);
549 if (tmp == NULL) {
550- _gnutls_name_constraints_node_free(dest);
551- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
552+ gnutls_assert();
553+ ret = GNUTLS_E_MEMORY_ERROR;
554+ goto cleanup;
555+ }
556+ ret = name_constraints_node_list_add(excluded, tmp);
557+ if (ret < 0) {
558+ gnutls_assert();
559+ goto cleanup;
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,
565- NULL, 32);
566+ tmp = name_constraints_node_new(
567+ nc, GNUTLS_SAN_IPADDRESS, NULL, 32);
568 if (tmp == NULL) {
569- _gnutls_name_constraints_node_free(dest);
570- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
571+ gnutls_assert();
572+ ret = GNUTLS_E_MEMORY_ERROR;
573+ goto cleanup;
574+ }
575+ ret = name_constraints_node_list_add(excluded, tmp);
576+ if (ret < 0) {
577+ gnutls_assert();
578+ goto cleanup;
579 }
580- tmp->next = *_nc_excluded;
581- *_nc_excluded = tmp;
582 break;
583 case GNUTLS_SAN_DNSNAME:
584 case GNUTLS_SAN_RFC822NAME:
585- tmp = name_constraints_node_new(type, NULL, 0);
586+ tmp = name_constraints_node_new(nc, type, NULL, 0);
587 if (tmp == NULL) {
588- _gnutls_name_constraints_node_free(dest);
589- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
590+ gnutls_assert();
591+ ret = GNUTLS_E_MEMORY_ERROR;
592+ goto cleanup;
593+ }
594+ ret = name_constraints_node_list_add(excluded, tmp);
595+ if (ret < 0) {
596+ gnutls_assert();
597+ goto cleanup;
598 }
599- tmp->next = *_nc_excluded;
600- *_nc_excluded = tmp;
601 break;
602 default: // do nothing, at least one node was already moved in phase 1
603 break;
604 }
605 }
606- return GNUTLS_E_SUCCESS;
607+ ret = GNUTLS_E_SUCCESS;
608+
609+cleanup:
610+ gnutls_free(removed.data);
611+ return ret;
612 }
613
614-static int _gnutls_name_constraints_append(name_constraints_node_st **_nc,
615- name_constraints_node_st *_nc2)
616+static int name_constraints_node_list_concat(
617+ gnutls_x509_name_constraints_t nc,
618+ struct name_constraints_node_list_st *nodes,
619+ const struct name_constraints_node_list_st *nodes2)
620 {
621- name_constraints_node_st *nc, *nc2;
622- struct name_constraints_node_st *tmp;
623-
624- if (_nc2 == NULL)
625- return 0;
626-
627- nc2 = _nc2;
628- while (nc2) {
629- nc = *_nc;
630-
631- tmp = name_constraints_node_new(nc2->type, nc2->name.data,
632- nc2->name.size);
633- if (tmp == NULL)
634+ for (size_t i = 0; i < nodes2->size; i++) {
635+ const struct name_constraints_node_st *node = nodes2->data[i];
636+ struct name_constraints_node_st *tmp;
637+ int ret;
638+
639+ tmp = name_constraints_node_new(nc, node->type, node->name.data,
640+ node->name.size);
641+ if (tmp == NULL) {
642 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
643-
644- tmp->next = nc;
645- *_nc = tmp;
646-
647- nc2 = nc2->next;
648+ }
649+ ret = name_constraints_node_list_add(nodes, tmp);
650+ if (ret < 0) {
651+ name_constraints_node_free(tmp);
652+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
653+ }
654 }
655
656 return 0;
657@@ -524,6 +608,25 @@ cleanup:
658 return ret;
659 }
660
661+void _gnutls_x509_name_constraints_clear(gnutls_x509_name_constraints_t nc)
662+{
663+ for (size_t i = 0; i < nc->nodes.size; i++) {
664+ struct name_constraints_node_st *node = nc->nodes.data[i];
665+ name_constraints_node_free(node);
666+ }
667+ gnutls_free(nc->nodes.data);
668+ nc->nodes.capacity = 0;
669+ nc->nodes.size = 0;
670+
671+ gnutls_free(nc->permitted.data);
672+ nc->permitted.capacity = 0;
673+ nc->permitted.size = 0;
674+
675+ gnutls_free(nc->excluded.data);
676+ nc->excluded.capacity = 0;
677+ nc->excluded.size = 0;
678+}
679+
680 /**
681 * gnutls_x509_name_constraints_deinit:
682 * @nc: The nameconstraints
683@@ -534,9 +637,7 @@ cleanup:
684 **/
685 void gnutls_x509_name_constraints_deinit(gnutls_x509_name_constraints_t nc)
686 {
687- _gnutls_name_constraints_node_free(nc->permitted);
688- _gnutls_name_constraints_node_free(nc->excluded);
689-
690+ _gnutls_x509_name_constraints_clear(nc);
691 gnutls_free(nc);
692 }
693
694@@ -552,12 +653,15 @@ void gnutls_x509_name_constraints_deinit(gnutls_x509_name_constraints_t nc)
695 **/
696 int gnutls_x509_name_constraints_init(gnutls_x509_name_constraints_t *nc)
697 {
698- *nc = gnutls_calloc(1, sizeof(struct gnutls_name_constraints_st));
699- if (*nc == NULL) {
700+ struct gnutls_name_constraints_st *tmp;
701+
702+ tmp = gnutls_calloc(1, sizeof(struct gnutls_name_constraints_st));
703+ if (tmp == NULL) {
704 gnutls_assert();
705 return GNUTLS_E_MEMORY_ERROR;
706 }
707
708+ *nc = tmp;
709 return 0;
710 }
711
712@@ -565,36 +669,25 @@ static int name_constraints_add(gnutls_x509_name_constraints_t nc,
713 gnutls_x509_subject_alt_name_t type,
714 const gnutls_datum_t *name, unsigned permitted)
715 {
716- struct name_constraints_node_st *tmp, *prev = NULL;
717+ struct name_constraints_node_st *tmp;
718+ struct name_constraints_node_list_st *nodes;
719 int ret;
720
721 ret = validate_name_constraints_node(type, name);
722 if (ret < 0)
723 return gnutls_assert_val(ret);
724
725- if (permitted != 0)
726- prev = tmp = nc->permitted;
727- else
728- prev = tmp = nc->excluded;
729+ nodes = permitted ? &nc->permitted : &nc->excluded;
730
731- while (tmp != NULL) {
732- tmp = tmp->next;
733- if (tmp != NULL)
734- prev = tmp;
735- }
736-
737- tmp = name_constraints_node_new(type, name->data, name->size);
738+ tmp = name_constraints_node_new(nc, type, name->data, name->size);
739 if (tmp == NULL)
740 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
741- tmp->next = NULL;
742
743- if (prev == NULL) {
744- if (permitted != 0)
745- nc->permitted = tmp;
746- else
747- nc->excluded = tmp;
748- } else
749- prev->next = tmp;
750+ ret = name_constraints_node_list_add(nodes, tmp);
751+ if (ret < 0) {
752+ name_constraints_node_free(tmp);
753+ return gnutls_assert_val(ret);
754+ }
755
756 return 0;
757 }
758@@ -620,14 +713,15 @@ int _gnutls_x509_name_constraints_merge(gnutls_x509_name_constraints_t nc,
759 {
760 int ret;
761
762- ret = _gnutls_name_constraints_intersect(&nc->permitted, nc2->permitted,
763- &nc->excluded);
764+ ret = name_constraints_node_list_intersect(
765+ nc, &nc->permitted, &nc2->permitted, &nc->excluded);
766 if (ret < 0) {
767 gnutls_assert();
768 return ret;
769 }
770
771- ret = _gnutls_name_constraints_append(&nc->excluded, nc2->excluded);
772+ ret = name_constraints_node_list_concat(nc, &nc->excluded,
773+ &nc2->excluded);
774 if (ret < 0) {
775 gnutls_assert();
776 return ret;
777@@ -804,50 +898,51 @@ static unsigned email_matches(const gnutls_datum_t *name,
778 *
779 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
780 -*/
781-static int
782-name_constraints_intersect_nodes(name_constraints_node_st *nc1,
783- name_constraints_node_st *nc2,
784- name_constraints_node_st **_intersection)
785+static int name_constraints_intersect_nodes(
786+ gnutls_x509_name_constraints_t nc,
787+ const struct name_constraints_node_st *node1,
788+ const struct name_constraints_node_st *node2,
789+ struct name_constraints_node_st **_intersection)
790 {
791 // presume empty intersection
792- name_constraints_node_st *intersection = NULL;
793- name_constraints_node_st *to_copy = NULL;
794+ struct name_constraints_node_st *intersection = NULL;
795+ const struct name_constraints_node_st *to_copy = NULL;
796 unsigned iplength = 0;
797 unsigned byte;
798
799 *_intersection = NULL;
800
801- if (nc1->type != nc2->type) {
802+ if (node1->type != node2->type) {
803 return GNUTLS_E_SUCCESS;
804 }
805- switch (nc1->type) {
806+ switch (node1->type) {
807 case GNUTLS_SAN_DNSNAME:
808- if (!dnsname_matches(&nc2->name, &nc1->name))
809+ if (!dnsname_matches(&node2->name, &node1->name))
810 return GNUTLS_E_SUCCESS;
811- to_copy = nc2;
812+ to_copy = node2;
813 break;
814 case GNUTLS_SAN_RFC822NAME:
815- if (!email_matches(&nc2->name, &nc1->name))
816+ if (!email_matches(&node2->name, &node1->name))
817 return GNUTLS_E_SUCCESS;
818- to_copy = nc2;
819+ to_copy = node2;
820 break;
821 case GNUTLS_SAN_IPADDRESS:
822- if (nc1->name.size != nc2->name.size)
823+ if (node1->name.size != node2->name.size)
824 return GNUTLS_E_SUCCESS;
825- iplength = nc1->name.size / 2;
826+ iplength = node1->name.size / 2;
827 for (byte = 0; byte < iplength; byte++) {
828- if (((nc1->name.data[byte] ^
829- nc2->name.data[byte]) // XOR of addresses
830- &
831- nc1->name.data[byte + iplength] // AND mask from nc1
832- &
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@@ -856,8 +951,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(
855- to_copy->type, to_copy->name.data, to_copy->name.size);
856+ *_intersection = name_constraints_node_new(nc, to_copy->type,
857+ to_copy->name.data,
858+ to_copy->name.size);
859 if (*_intersection == NULL)
860 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
861 intersection = *_intersection;
862@@ -869,12 +965,12 @@ name_constraints_intersect_nodes(name_constraints_node_st *nc1,
863 _gnutls_mask_ip(intersection->name.data,
864 intersection->name.data + iplength,
865 iplength);
866- _gnutls_mask_ip(nc1->name.data,
867- nc1->name.data + iplength, iplength);
868+ _gnutls_mask_ip(node1->name.data,
869+ node1->name.data + iplength, iplength);
870 // update intersection, if necessary (we already know one is subset of other)
871 for (byte = 0; byte < 2 * iplength; byte++) {
872 intersection->name.data[byte] |=
873- nc1->name.data[byte];
874+ node1->name.data[byte];
875 }
876 }
877 }
878@@ -1177,10 +1273,17 @@ gnutls_x509_name_constraints_check_crt(gnutls_x509_name_constraints_t nc,
879 unsigned idx, t, san_type;
880 gnutls_datum_t n;
881 unsigned found_one;
882+ size_t checks;
883
884- if (is_nc_empty(nc, type) != 0)
885+ if (_gnutls_x509_name_constraints_is_empty(nc, type) != 0)
886 return 1; /* shortcut; no constraints to check */
887
888+ if (!INT_ADD_OK(nc->permitted.size, nc->excluded.size, &checks) ||
889+ !INT_MULTIPLY_OK(checks, cert->san->size, &checks) ||
890+ checks > MAX_NC_CHECKS) {
891+ return gnutls_assert_val(0);
892+ }
893+
894 if (type == GNUTLS_SAN_RFC822NAME) {
895 found_one = 0;
896 for (idx = 0;; idx++) {
897@@ -1378,20 +1481,13 @@ int gnutls_x509_name_constraints_get_permitted(gnutls_x509_name_constraints_t nc
898 unsigned idx, unsigned *type,
899 gnutls_datum_t *name)
900 {
901- unsigned int i;
902- struct name_constraints_node_st *tmp = nc->permitted;
903+ const struct name_constraints_node_st *tmp;
904
905- for (i = 0; i < idx; i++) {
906- if (tmp == NULL)
907- return gnutls_assert_val(
908- GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
909-
910- tmp = tmp->next;
911- }
912-
913- if (tmp == NULL)
914+ if (idx >= nc->permitted.size)
915 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
916
917+ tmp = nc->permitted.data[idx];
918+
919 *type = tmp->type;
920 *name = tmp->name;
921
922@@ -1421,20 +1517,13 @@ int gnutls_x509_name_constraints_get_excluded(gnutls_x509_name_constraints_t nc,
923 unsigned idx, unsigned *type,
924 gnutls_datum_t *name)
925 {
926- unsigned int i;
927- struct name_constraints_node_st *tmp = nc->excluded;
928+ const struct name_constraints_node_st *tmp;
929
930- for (i = 0; i < idx; i++) {
931- if (tmp == NULL)
932- return gnutls_assert_val(
933- GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
934-
935- tmp = tmp->next;
936- }
937-
938- if (tmp == NULL)
939+ if (idx >= nc->excluded.size)
940 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
941
942+ tmp = nc->excluded.data[idx];
943+
944 *type = tmp->type;
945 *name = tmp->name;
946
947diff --git a/lib/x509/x509_ext.c b/lib/x509/x509_ext.c
948index ad3af1430..064ca8357 100644
949--- a/lib/x509/x509_ext.c
950+++ b/lib/x509/x509_ext.c
951@@ -34,10 +34,6 @@
952 #include "intprops.h"
953
954 #define MAX_ENTRIES 64
955-struct gnutls_subject_alt_names_st {
956- struct name_st *names;
957- unsigned int size;
958-};
959
960 /**
961 * gnutls_subject_alt_names_init:
962@@ -389,22 +385,15 @@ int gnutls_x509_ext_import_name_constraints(const gnutls_datum_t *ext,
963 }
964
965 if (flags & GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND &&
966- (nc->permitted != NULL || nc->excluded != NULL)) {
967+ !_gnutls_x509_name_constraints_is_empty(nc, 0)) {
968 ret = gnutls_x509_name_constraints_init(&nc2);
969 if (ret < 0) {
970 gnutls_assert();
971 goto cleanup;
972 }
973
974- ret = _gnutls_extract_name_constraints(c2, "permittedSubtrees",
975- &nc2->permitted);
976- if (ret < 0) {
977- gnutls_assert();
978- goto cleanup;
979- }
980-
981- ret = _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@@ -416,18 +405,10 @@ 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+ _gnutls_x509_name_constraints_clear(nc);
995
996- ret = _gnutls_extract_name_constraints(c2, "permittedSubtrees",
997- &nc->permitted);
998- if (ret < 0) {
999- gnutls_assert();
1000- goto cleanup;
1001- }
1002-
1003- ret = _gnutls_extract_name_constraints(c2, "excludedSubtrees",
1004- &nc->excluded);
1005+ ret = _gnutls_x509_name_constraints_extract(
1006+ c2, "permittedSubtrees", "excludedSubtrees", nc);
1007 if (ret < 0) {
1008 gnutls_assert();
1009 goto cleanup;
1010@@ -463,9 +444,10 @@ int gnutls_x509_ext_export_name_constraints(gnutls_x509_name_constraints_t nc,
1011 int ret, result;
1012 uint8_t null = 0;
1013 asn1_node c2 = NULL;
1014- struct name_constraints_node_st *tmp;
1015+ unsigned rtype;
1016+ gnutls_datum_t rname;
1017
1018- if (nc->permitted == NULL && nc->excluded == NULL)
1019+ if (_gnutls_x509_name_constraints_is_empty(nc, 0))
1020 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1021
1022 result = asn1_create_element(_gnutls_get_pkix(),
1023@@ -475,11 +457,20 @@ int gnutls_x509_ext_export_name_constraints(gnutls_x509_name_constraints_t nc,
1024 return _gnutls_asn2err(result);
1025 }
1026
1027- if (nc->permitted == NULL) {
1028+ ret = gnutls_x509_name_constraints_get_permitted(nc, 0, &rtype, &rname);
1029+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1030 (void)asn1_write_value(c2, "permittedSubtrees", NULL, 0);
1031 } else {
1032- tmp = nc->permitted;
1033- do {
1034+ for (unsigned i = 0;; i++) {
1035+ ret = gnutls_x509_name_constraints_get_permitted(
1036+ nc, i, &rtype, &rname);
1037+ if (ret < 0) {
1038+ if (ret ==
1039+ GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1040+ break;
1041+ gnutls_assert();
1042+ goto cleanup;
1043+ }
1044 result = asn1_write_value(c2, "permittedSubtrees",
1045 "NEW", 1);
1046 if (result != ASN1_SUCCESS) {
1047@@ -506,21 +497,29 @@ int gnutls_x509_ext_export_name_constraints(gnutls_x509_name_constraints_t nc,
1048 }
1049
1050 ret = _gnutls_write_general_name(
1051- c2, "permittedSubtrees.?LAST.base", tmp->type,
1052- tmp->name.data, tmp->name.size);
1053+ c2, "permittedSubtrees.?LAST.base", rtype,
1054+ rname.data, rname.size);
1055 if (ret < 0) {
1056 gnutls_assert();
1057 goto cleanup;
1058 }
1059- tmp = tmp->next;
1060- } while (tmp != NULL);
1061+ }
1062 }
1063
1064- if (nc->excluded == NULL) {
1065+ ret = gnutls_x509_name_constraints_get_excluded(nc, 0, &rtype, &rname);
1066+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1067 (void)asn1_write_value(c2, "excludedSubtrees", NULL, 0);
1068 } else {
1069- tmp = nc->excluded;
1070- do {
1071+ for (unsigned i = 0;; i++) {
1072+ ret = gnutls_x509_name_constraints_get_excluded(
1073+ nc, i, &rtype, &rname);
1074+ if (ret < 0) {
1075+ if (ret ==
1076+ GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1077+ break;
1078+ gnutls_assert();
1079+ goto cleanup;
1080+ }
1081 result = asn1_write_value(c2, "excludedSubtrees", "NEW",
1082 1);
1083 if (result != ASN1_SUCCESS) {
1084@@ -546,14 +545,13 @@ int gnutls_x509_ext_export_name_constraints(gnutls_x509_name_constraints_t nc,
1085 }
1086
1087 ret = _gnutls_write_general_name(
1088- c2, "excludedSubtrees.?LAST.base", tmp->type,
1089- tmp->name.data, tmp->name.size);
1090+ c2, "excludedSubtrees.?LAST.base", rtype,
1091+ rname.data, rname.size);
1092 if (ret < 0) {
1093 gnutls_assert();
1094 goto cleanup;
1095 }
1096- tmp = tmp->next;
1097- } while (tmp != NULL);
1098+ }
1099 }
1100
1101 ret = _gnutls_x509_der_encode(c2, "", ext, 0);
1102diff --git a/lib/x509/x509_ext_int.h b/lib/x509/x509_ext_int.h
1103index 558d61956..b37d74997 100644
1104--- a/lib/x509/x509_ext_int.h
1105+++ b/lib/x509/x509_ext_int.h
1106@@ -29,6 +29,11 @@ struct name_st {
1107 gnutls_datum_t othername_oid;
1108 };
1109
1110+struct gnutls_subject_alt_names_st {
1111+ struct name_st *names;
1112+ unsigned int size;
1113+};
1114+
1115 int _gnutls_alt_name_process(gnutls_datum_t *out, unsigned type,
1116 const gnutls_datum_t *san, unsigned raw);
1117
1118diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
1119index 4ec55bd75..211743ced 100644
1120--- a/lib/x509/x509_int.h
1121+++ b/lib/x509/x509_int.h
1122@@ -485,20 +485,13 @@ int _gnutls_x509_crt_check_revocation(gnutls_x509_crt_t cert,
1123 int crl_list_length,
1124 gnutls_verify_output_function func);
1125
1126-typedef struct gnutls_name_constraints_st {
1127- struct name_constraints_node_st *permitted;
1128- struct name_constraints_node_st *excluded;
1129-} gnutls_name_constraints_st;
1130-
1131-typedef struct name_constraints_node_st {
1132- unsigned type;
1133- gnutls_datum_t name;
1134- struct name_constraints_node_st *next;
1135-} name_constraints_node_st;
1136-
1137-int _gnutls_extract_name_constraints(asn1_node c2, const char *vstr,
1138- name_constraints_node_st **_nc);
1139-void _gnutls_name_constraints_node_free(name_constraints_node_st *node);
1140+bool _gnutls_x509_name_constraints_is_empty(gnutls_x509_name_constraints_t nc,
1141+ unsigned type);
1142+int _gnutls_x509_name_constraints_extract(asn1_node c2,
1143+ const char *permitted_name,
1144+ const char *excluded_name,
1145+ gnutls_x509_name_constraints_t nc);
1146+void _gnutls_x509_name_constraints_clear(gnutls_x509_name_constraints_t nc);
1147 int _gnutls_x509_name_constraints_merge(gnutls_x509_name_constraints_t nc,
1148 gnutls_x509_name_constraints_t nc2);
1149
diff --git a/meta/recipes-support/gnutls/gnutls_3.8.4.bb b/meta/recipes-support/gnutls/gnutls_3.8.4.bb
index 20139b4dd4..e77960724b 100644
--- a/meta/recipes-support/gnutls/gnutls_3.8.4.bb
+++ b/meta/recipes-support/gnutls/gnutls_3.8.4.bb
@@ -23,6 +23,7 @@ SRC_URI = "https://www.gnupg.org/ftp/gcrypt/gnutls/v${SHRT_VER}/gnutls-${PV}.tar
23 file://0001-Creating-.hmac-file-should-be-excuted-in-target-envi.patch \ 23 file://0001-Creating-.hmac-file-should-be-excuted-in-target-envi.patch \
24 file://run-ptest \ 24 file://run-ptest \
25 file://Add-ptest-support.patch \ 25 file://Add-ptest-support.patch \
26 file://CVE-2024-12243.patch \
26 " 27 "
27 28
28SRC_URI[sha256sum] = "2bea4e154794f3f00180fa2a5c51fe8b005ac7a31cd58bd44cdfa7f36ebc3a9b" 29SRC_URI[sha256sum] = "2bea4e154794f3f00180fa2a5c51fe8b005ac7a31cd58bd44cdfa7f36ebc3a9b"