From f341441fad91142897d83b44a175ffc8f925b76f Mon Sep 17 00:00:00 2001
From: Joshua Rogers <joshua@joshua.hu>
Date: Tue, 21 Apr 2026 18:11:39 +0200
Subject: [PATCH] buffers: fix handshake_compare when sequence numbers match

The comparator function used for ordering DTLS packets
by sequence numbers did not follow qsort comparator contracts
in case of packets with duplicate sequence numbers,
which could lead to unstable ordering or undefined behaviour.
Returning 0 in such cases makes the sorting stable.

Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
Fixes: #1848
Fixes: CVE-2026-42009
Fixes: GNUTLS-SA-2026-04-29-2
CVSS: 7.5 High CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Signed-off-by: Joshua Rogers <joshua@joshua.hu>
---
 lib/buffers.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

From f01e21441e29052a6f0963840794c41d3b3ee66d Mon Sep 17 00:00:00 2001
From: Alexander Sosedkin <asosedkin@redhat.com>
Date: Tue, 21 Apr 2026 16:52:48 +0200
Subject: lib/buffers: ensure packets have differing sequence
 numbers

There should normally be no packets with same sequence number and
differing handshake type, unless an adversary crafts them.
Discarding them allows to get rid of packets
with duplicate sequence ID in the buffer,
relieving us from the question of how to sort them later.

Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
Fixes: #1848
Fixes: CVE-2026-42009
Fixes: GNUTLS-SA-2026-04-29-2
CVSS: 7.5 High CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
---
 lib/buffers.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

Index: gnutls-3.8.10/lib/buffers.c
===================================================================
--- gnutls-3.8.10.orig/lib/buffers.c
+++ gnutls-3.8.10/lib/buffers.c
@@ -844,11 +844,7 @@ static int handshake_compare(const void
 {
 	const handshake_buffer_st *e1 = _e1;
 	const handshake_buffer_st *e2 = _e2;
-
-	if (e1->sequence <= e2->sequence)
-		return 1;
-	else
-		return -1;
+	return (e1->sequence < e2->sequence) - (e1->sequence > e2->sequence);
 }
 
 #define SSL2_HEADERS 1
@@ -971,8 +967,20 @@ static int merge_handshake_packet(gnutls
 		session->internals.handshake_recv_buffer;
 
 	for (i = 0; i < session->internals.handshake_recv_buffer_size; i++) {
-		if (recv_buf[i].htype == hsk->htype &&
-		    recv_buf[i].sequence == hsk->sequence) {
+		if (recv_buf[i].sequence == hsk->sequence) {
+			if (recv_buf[i].htype != hsk->htype) {
+				_gnutls_audit_log(
+					session,
+					"Discarded unexpected handshake packet "
+					"with duplicate sequence %d, but "
+					"mismatched type %s (previously %s)\n",
+					hsk->sequence,
+					_gnutls_handshake2str(hsk->htype),
+					_gnutls_handshake2str(
+						recv_buf[i].htype));
+				_gnutls_handshake_buffer_clear(hsk);
+				return 0;
+			}
 			exists = 1;
 			pos = i;
 			break;
