import CS git gnutls-3.6.16-8.el8_10.6
This commit is contained in:
parent
fdb3259542
commit
09d4f85c6e
226
SOURCES/gnutls-3.6.16-1808-psk-rehandshake.patch
Normal file
226
SOURCES/gnutls-3.6.16-1808-psk-rehandshake.patch
Normal file
@ -0,0 +1,226 @@
|
||||
From 35dbb0e4ebcc07acecfd060ffc6ca076cf397920 Mon Sep 17 00:00:00 2001
|
||||
From: Joshua Rogers <joshua@joshua.hu>
|
||||
Date: Wed, 18 Mar 2026 17:08:03 +0100
|
||||
Subject: [PATCH 1/3] handshake-checks: fix username comparison during
|
||||
rehandshake
|
||||
|
||||
This is definitely a security issue
|
||||
subverting the GNUTLS_ALLOW_ID_CHANGE protection,
|
||||
but its real-life exploitability is under question.
|
||||
|
||||
Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
|
||||
Fixes: #1808
|
||||
Signed-off-by: Joshua Rogers <joshua@joshua.hu>
|
||||
---
|
||||
lib/handshake-checks.c | 15 ++++++++++-----
|
||||
1 file changed, 10 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/lib/handshake-checks.c b/lib/handshake-checks.c
|
||||
index b07b9680c..e02210531 100644
|
||||
--- a/lib/handshake-checks.c
|
||||
+++ b/lib/handshake-checks.c
|
||||
@@ -75,11 +75,16 @@ int _gnutls_check_id_for_change(gnutls_session_t session)
|
||||
if (username == NULL)
|
||||
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
|
||||
|
||||
- if (session->internals.saved_username_size != -1) {
|
||||
- if (session->internals.saved_username_size == username_length &&
|
||||
- strncmp(session->internals.saved_username, username, username_length) != 0) {
|
||||
- _gnutls_debug_log("Session's PSK username changed during rehandshake; aborting!\n");
|
||||
- return gnutls_assert_val(GNUTLS_E_SESSION_USER_ID_CHANGED);
|
||||
+ if (session->internals.saved_username &&
|
||||
+ session->internals.saved_username_size != -1) {
|
||||
+ if (session->internals.saved_username_size !=
|
||||
+ username_length ||
|
||||
+ memcmp(session->internals.saved_username, username,
|
||||
+ username_length)) {
|
||||
+ _gnutls_debug_log(
|
||||
+ "Session's PSK username changed during rehandshake; aborting!\n");
|
||||
+ return gnutls_assert_val(
|
||||
+ GNUTLS_E_SESSION_USER_ID_CHANGED);
|
||||
}
|
||||
} else {
|
||||
memcpy(session->internals.saved_username, username, username_length);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 7153b4668234f2687cab354c418b40624a650567 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Wed, 18 Mar 2026 16:08:51 +0100
|
||||
Subject: [PATCH 2/3] tests/rehandshake-switch-psk-id: refactor a bit
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/rehandshake-switch-psk-id.c | 50 ++++++++++++++++++-------------
|
||||
1 file changed, 29 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/tests/rehandshake-switch-psk-id.c b/tests/rehandshake-switch-psk-id.c
|
||||
index c8beec13f..62593060a 100644
|
||||
--- a/tests/rehandshake-switch-psk-id.c
|
||||
+++ b/tests/rehandshake-switch-psk-id.c
|
||||
@@ -24,10 +24,10 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
+#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
-#include <errno.h>
|
||||
#include <gnutls/gnutls.h>
|
||||
#include "utils.h"
|
||||
#include "eagain-common.h"
|
||||
@@ -35,6 +35,8 @@
|
||||
/* This test checks whether the server switching certificates is detected
|
||||
* by the client */
|
||||
|
||||
+#define SIZEOF(array) (sizeof(array) / sizeof(array[0]))
|
||||
+
|
||||
const char *side;
|
||||
|
||||
static void tls_log_func(int level, const char *str)
|
||||
@@ -42,11 +44,8 @@ static void tls_log_func(int level, const char *str)
|
||||
fprintf(stderr, "%s|<%d>| %s", side, level, str);
|
||||
}
|
||||
|
||||
-#include "cert-common.h"
|
||||
-
|
||||
-static int
|
||||
-pskfunc(gnutls_session_t session, const char *username,
|
||||
- gnutls_datum_t * key)
|
||||
+static int pskfunc(gnutls_session_t session, const char *username,
|
||||
+ gnutls_datum_t *key)
|
||||
{
|
||||
if (debug)
|
||||
printf("psk: username %s\n", username);
|
||||
@@ -76,6 +75,9 @@ static void try(const char *prio, gnutls_kx_algorithm_t kx, unsigned allow_chang
|
||||
const gnutls_datum_t key = { (void *) "DEADBEEF", 8 };
|
||||
int cret = GNUTLS_E_AGAIN;
|
||||
|
||||
+ success("testing: prio=%s kx=%s allow_change=%d\n", prio,
|
||||
+ gnutls_kx_get_name(kx), allow_change);
|
||||
+
|
||||
/* General init. */
|
||||
gnutls_global_set_log_function(tls_log_func);
|
||||
if (debug)
|
||||
@@ -170,22 +172,28 @@ static void try(const char *prio, gnutls_kx_algorithm_t kx, unsigned allow_chang
|
||||
|
||||
void doit(void)
|
||||
{
|
||||
+ const char *prio_list[] = {
|
||||
+ "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK",
|
||||
+ "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-PSK",
|
||||
+ "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-PSK",
|
||||
+ };
|
||||
+ const gnutls_kx_algorithm_t kx_list[] = {
|
||||
+ GNUTLS_KX_PSK,
|
||||
+ GNUTLS_KX_DHE_PSK,
|
||||
+ GNUTLS_KX_ECDHE_PSK,
|
||||
+ };
|
||||
+ assert(SIZEOF(prio_list) == SIZEOF(kx_list));
|
||||
+
|
||||
global_init();
|
||||
|
||||
- /* Allow change of ID */
|
||||
- try("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", GNUTLS_KX_PSK, 0);
|
||||
- reset_buffers();
|
||||
- try("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-PSK", GNUTLS_KX_DHE_PSK, 0);
|
||||
- reset_buffers();
|
||||
- try("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-PSK", GNUTLS_KX_ECDHE_PSK, 0);
|
||||
- reset_buffers();
|
||||
-
|
||||
- /* Prohibit (default) change of ID */
|
||||
- try("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", GNUTLS_KX_PSK, 1);
|
||||
- reset_buffers();
|
||||
- try("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-PSK", GNUTLS_KX_DHE_PSK, 1);
|
||||
- reset_buffers();
|
||||
- try("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-PSK", GNUTLS_KX_ECDHE_PSK, 1);
|
||||
- reset_buffers();
|
||||
+ /* loop over allowed (0) and disallowed (1) ID change */
|
||||
+ for (unsigned allow = 0; allow <= 1; allow++) {
|
||||
+ /* loop over priority strings/key exchange algorithms */
|
||||
+ for (unsigned i = 0; i < SIZEOF(prio_list); i++) {
|
||||
+ try(prio_list[i], kx_list[i], allow);
|
||||
+ reset_buffers();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
gnutls_global_deinit();
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From cb3b9c873555d3e458205cb554153553c7baaaae Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Wed, 18 Mar 2026 16:47:43 +0100
|
||||
Subject: [PATCH 3/3] tests/rehandshake-switch-psk-id: test usernames of varied
|
||||
length
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/rehandshake-switch-psk-id.c | 20 ++++++++++++++------
|
||||
1 file changed, 14 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/tests/rehandshake-switch-psk-id.c b/tests/rehandshake-switch-psk-id.c
|
||||
index 62593060a..5e06abe05 100644
|
||||
--- a/tests/rehandshake-switch-psk-id.c
|
||||
+++ b/tests/rehandshake-switch-psk-id.c
|
||||
@@ -58,7 +58,8 @@ static int pskfunc(gnutls_session_t session, const char *username,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static void try(const char *prio, gnutls_kx_algorithm_t kx, unsigned allow_change)
|
||||
+static void try(const char *prio, gnutls_kx_algorithm_t kx,
|
||||
+ unsigned allow_change, const char *username)
|
||||
{
|
||||
int ret;
|
||||
/* Server stuff. */
|
||||
@@ -75,8 +76,8 @@ static void try(const char *prio, gnutls_kx_algorithm_t kx, unsigned allow_chang
|
||||
const gnutls_datum_t key = { (void *) "DEADBEEF", 8 };
|
||||
int cret = GNUTLS_E_AGAIN;
|
||||
|
||||
- success("testing: prio=%s kx=%s allow_change=%d\n", prio,
|
||||
- gnutls_kx_get_name(kx), allow_change);
|
||||
+ success("testing: prio=%s kx=%s allow_change=%d username=%s\n", prio,
|
||||
+ gnutls_kx_get_name(kx), allow_change, username);
|
||||
|
||||
/* General init. */
|
||||
gnutls_global_set_log_function(tls_log_func);
|
||||
@@ -120,7 +121,7 @@ static void try(const char *prio, gnutls_kx_algorithm_t kx, unsigned allow_chang
|
||||
if (ret < 0)
|
||||
exit(1);
|
||||
|
||||
- gnutls_psk_set_client_credentials(clientpskcred2, "test2", &key,
|
||||
+ gnutls_psk_set_client_credentials(clientpskcred2, username, &key,
|
||||
GNUTLS_PSK_KEY_HEX);
|
||||
|
||||
ret = gnutls_init(&client, GNUTLS_CLIENT);
|
||||
@@ -184,14 +185,21 @@ void doit(void)
|
||||
};
|
||||
assert(SIZEOF(prio_list) == SIZEOF(kx_list));
|
||||
|
||||
+ /* same length, different length */
|
||||
+ const char *usernames[] = { "test2", "test3-but-longer" };
|
||||
+
|
||||
global_init();
|
||||
|
||||
/* loop over allowed (0) and disallowed (1) ID change */
|
||||
for (unsigned allow = 0; allow <= 1; allow++) {
|
||||
/* loop over priority strings/key exchange algorithms */
|
||||
for (unsigned i = 0; i < SIZEOF(prio_list); i++) {
|
||||
- try(prio_list[i], kx_list[i], allow);
|
||||
- reset_buffers();
|
||||
+ /* loop over usernames to rehandshake to */
|
||||
+ for (unsigned j = 0; j < SIZEOF(usernames); j++) {
|
||||
+ try(prio_list[i], kx_list[i], allow,
|
||||
+ usernames[j]);
|
||||
+ reset_buffers();
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
1474
SOURCES/gnutls-3.6.16-1810-ocsp-truncated-eku.patch
Normal file
1474
SOURCES/gnutls-3.6.16-1810-ocsp-truncated-eku.patch
Normal file
File diff suppressed because it is too large
Load Diff
35
SOURCES/gnutls-3.6.16-1817-security-parameters.patch
Normal file
35
SOURCES/gnutls-3.6.16-1817-security-parameters.patch
Normal file
@ -0,0 +1,35 @@
|
||||
From 4e8d3ba9160dfd3155c2fab12e9d5ab973013c2d Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Tue, 7 Apr 2026 10:16:03 +0200
|
||||
Subject: [PATCH] session_pack: validate session_id_size on unpacking
|
||||
|
||||
A check for session_id_size not exceeding GNUTLS_MAX_SESSION_ID_SIZE
|
||||
on loading persisted TLS session data was overlooked,
|
||||
leading to a heap overflow
|
||||
were the data corrupted in a malicious manner.
|
||||
|
||||
Reported-by: Haruto Kimura (Stella)
|
||||
Fixes: #1817
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/session_pack.c | 12 +++++++-----
|
||||
1 file changed, 7 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/lib/session_pack.c b/lib/session_pack.c
|
||||
index a6d11c4cf..823824e4c 100644
|
||||
--- a/lib/session_pack.c
|
||||
+++ b/lib/session_pack.c
|
||||
@@ -1006,6 +1006,10 @@ unpack_security_parameters(gnutls_session_t session, gnutls_buffer_st * ps)
|
||||
&session->internals.resumed_security_parameters.
|
||||
session_id_size, 1);
|
||||
|
||||
+ if (session->internals.resumed_security_parameters.session_id_size >
|
||||
+ GNUTLS_MAX_SESSION_ID_SIZE)
|
||||
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
||||
+
|
||||
BUFFER_POP(ps,
|
||||
session->internals.resumed_security_parameters.
|
||||
session_id,
|
||||
--
|
||||
2.53.0
|
||||
|
||||
116
SOURCES/gnutls-3.6.16-1818-pem-parsing.patch
Normal file
116
SOURCES/gnutls-3.6.16-1818-pem-parsing.patch
Normal file
@ -0,0 +1,116 @@
|
||||
From 09f3ab24fba0d2558db29c0e47b011f9b9b56c09 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Tue, 7 Apr 2026 20:23:29 +0200
|
||||
Subject: [PATCH 1/2] lib/x509/privkey_openssl: mind header size more carefully
|
||||
|
||||
When parsing private keys in OpenSSL PEM format, GnuTLS did not perform
|
||||
sufficient bounds checking for the length of the PEM header being parsed.
|
||||
For specially crafted inputs, this could lead to heap overreads.
|
||||
There was no confidentiality risk and
|
||||
the crash potential was limited to instrumented builds in practice.
|
||||
This change instates the overlooked bounds checking.
|
||||
|
||||
Reported-by: Kamil Frankowicz <kamil.frankowicz@cert.pl>
|
||||
Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
|
||||
Related: #1818
|
||||
Fixes: #1854
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/x509/privkey_openssl.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/x509/privkey_openssl.c b/lib/x509/privkey_openssl.c
|
||||
index 9fc70e032..b81671e7f 100644
|
||||
--- a/lib/x509/privkey_openssl.c
|
||||
+++ b/lib/x509/privkey_openssl.c
|
||||
@@ -174,7 +174,8 @@ gnutls_x509_privkey_import_openssl(gnutls_x509_privkey_t key,
|
||||
|
||||
for (i = 0; i < sizeof(pem_ciphers) / sizeof(pem_ciphers[0]); i++) {
|
||||
l = strlen(pem_ciphers[i].name);
|
||||
- if (!strncmp(pem_header, pem_ciphers[i].name, l) &&
|
||||
+ if (pem_header_size > l &&
|
||||
+ !strncmp(pem_header, pem_ciphers[i].name, l) &&
|
||||
pem_header[l] == ',') {
|
||||
pem_header += l + 1;
|
||||
cipher = pem_ciphers[i].cipher;
|
||||
@@ -225,6 +226,8 @@ gnutls_x509_privkey_import_openssl(gnutls_x509_privkey_t key,
|
||||
while (*pem_header == '\n' || *pem_header == '\r')
|
||||
pem_header++;
|
||||
|
||||
+ pem_header_size =
|
||||
+ data->size - (ptrdiff_t)(pem_header - pem_header_start);
|
||||
ret =
|
||||
_gnutls_base64_decode((const void *) pem_header,
|
||||
pem_header_size, &b64_data);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 3023e4d155affad82a42e1f076b73c5bf17c5931 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Tue, 7 Apr 2026 20:31:49 +0200
|
||||
Subject: [PATCH 2/2] tests/key-openssl: add a test for #1818.4 OpenSSL PEM
|
||||
parsing
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/key-openssl.c | 37 +++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 37 insertions(+)
|
||||
|
||||
diff --git a/tests/key-openssl.c b/tests/key-openssl.c
|
||||
index d2c8a724b..0e1e74804 100644
|
||||
--- a/tests/key-openssl.c
|
||||
+++ b/tests/key-openssl.c
|
||||
@@ -95,6 +95,21 @@ const char key2[] =
|
||||
"F3bDyqlxSOm7uxF/K3YzI44v8/D8GGnLBTpN+ANBdiY=\n"
|
||||
"-----END RSA PRIVATE KEY-----\n";
|
||||
|
||||
+const char key_newlines_head[] = /* key2... */
|
||||
+ "-----BEGIN RSA PRIVATE KEY-----\n"
|
||||
+ "Proc-Type: 4,ENCRYPTED\n"
|
||||
+ "DEK-Info: AES-128-CBC,2A57FF97B701B3F760145D7446929481\n";
|
||||
+/* ... with many newlines inserted in here */
|
||||
+const char key_newlines_tail[] =
|
||||
+ "mGAPhSw48wZBnkHOhfMDg8yL2IBgMuTmeKE4xoHi7T6isHBNfkqMd0iJ+DJP/OKb\n"
|
||||
+ "t+7lkKjj/xQ7w/bOBvBxlfRe4MW6+ejCdAFD9XSolW6WN6CEJPMI4UtmOK5inqcC\n"
|
||||
+ "8l2l54f/VGrVN9uavU3KlXCjrd3Jp9B0Mu4Zh/UU4+EWs9rJAZfLIn+vHZ3OHetx\n"
|
||||
+ "g74LdV7nC7lt/fjxc1caNIfgHs40dUt9FVrnJvAtkcNMtcjX/D+L8ZrLgQzIWFcs\n"
|
||||
+ "WAbUZj7Me22mCli3RPET7Je37K59IzfWgbWFCGaNu3X02g5xtCfdcn/Uqy9eofH0\n"
|
||||
+ "YjKRhpgXPeGJCkoRqDeUHQNPpVP5HrzDZMVK3E4DC03C8qvgsYvuwYt3KkbG2fuA\n"
|
||||
+ "F3bDyqlxSOm7uxF/K3YzI44v8/D8GGnLBTpN+ANBdiY=\n";
|
||||
+/* "-----END RSA PRIVATE KEY-----\n"; intentionally omitted */
|
||||
+
|
||||
void doit(void)
|
||||
{
|
||||
gnutls_x509_privkey_t pkey;
|
||||
@@ -167,5 +182,27 @@ void doit(void)
|
||||
}
|
||||
gnutls_x509_privkey_deinit(pkey);
|
||||
|
||||
+ /* import_openssl with a key having too many newlines in the header,
|
||||
+ * (fails with #1818.4 unfixed under ASAN) */
|
||||
+ ret = gnutls_x509_privkey_init(&pkey);
|
||||
+ if (ret < 0)
|
||||
+ fail("gnutls_x509_privkey_init: %d\n", ret);
|
||||
+
|
||||
+ //gnutls_x509_privkey_set_pin_function(pkey, good_pwd_cb, NULL);
|
||||
+ key.size = 1024 * 1024 * 1024;
|
||||
+ key.data = gnutls_malloc(key.size);
|
||||
+ memset(key.data, '\n', key.size);
|
||||
+ memcpy(key.data, key_newlines_head, sizeof(key_newlines_head) - 1);
|
||||
+ memcpy(key.data + key.size - sizeof(key_newlines_tail),
|
||||
+ key_newlines_tail, sizeof(key_newlines_tail));
|
||||
+
|
||||
+ ret = gnutls_x509_privkey_import_openssl(pkey, &key, "a123456");
|
||||
+ if (ret != GNUTLS_E_BASE64_DECODING_ERROR) {
|
||||
+ fail("gnutls_x509_import_openssl (full of newlines): %s\n",
|
||||
+ gnutls_strerror(ret));
|
||||
+ }
|
||||
+ gnutls_free(key.data);
|
||||
+ gnutls_x509_privkey_deinit(pkey);
|
||||
+
|
||||
gnutls_global_deinit();
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
41
SOURCES/gnutls-3.6.16-1818-rsa-coprime.patch
Normal file
41
SOURCES/gnutls-3.6.16-1818-rsa-coprime.patch
Normal file
@ -0,0 +1,41 @@
|
||||
From f66b9933252ef90f9765124361b47951a34d456d Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Tue, 7 Apr 2026 20:18:40 +0200
|
||||
Subject: [PATCH] nettle/pk: check RSA key coprimality in verify_params
|
||||
|
||||
Previously, gnutls_privkey_verify_params has overlooked
|
||||
the scenario of p and q not being co-prime,
|
||||
and proceeded with undefined behaviour that was extremely likely
|
||||
to error out in practice anyway.
|
||||
Now it returns GNUTLS_E_PK_INVALID_PRIVKEY in this case.
|
||||
|
||||
Reported-by: Kamil Frankowicz <kamil.frankowicz@cert.pl>
|
||||
Related: #1818
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/nettle/pk.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
|
||||
index b19fe3804..9d1c97b86 100644
|
||||
--- a/lib/nettle/pk.c
|
||||
+++ b/lib/nettle/pk.c
|
||||
@@ -2911,9 +2911,12 @@ wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo,
|
||||
goto rsa_cleanup;
|
||||
}
|
||||
|
||||
- mpz_invert(TOMPZ(t1),
|
||||
- TOMPZ(params->params[RSA_PRIME2]),
|
||||
- TOMPZ(params->params[RSA_PRIME1]));
|
||||
+ if (!mpz_invert(TOMPZ(t1),
|
||||
+ TOMPZ(params->params[RSA_PRIME2]),
|
||||
+ TOMPZ(params->params[RSA_PRIME1]))) {
|
||||
+ ret = gnutls_assert_val(GNUTLS_E_PK_INVALID_PRIVKEY);
|
||||
+ goto rsa_cleanup;
|
||||
+ }
|
||||
if (_gnutls_mpi_cmp(t1, params->params[RSA_COEF])
|
||||
!= 0) {
|
||||
ret =
|
||||
--
|
||||
2.53.0
|
||||
|
||||
58
SOURCES/gnutls-3.6.16-1819-dblfree-mid-import.patch
Normal file
58
SOURCES/gnutls-3.6.16-1819-dblfree-mid-import.patch
Normal file
@ -0,0 +1,58 @@
|
||||
From 2799775899d630d211647d5c916b987746dd7fbf Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Fri, 10 Apr 2026 20:30:27 +0200
|
||||
Subject: [PATCH] lib/x509: fix cleanup when gnutls_x509_crt_list_import_pkcs11
|
||||
fails
|
||||
|
||||
Previously gnutls_x509_trust_list_remove_trust_file tried to free
|
||||
the entire xcrt_list, even though one source of failures is
|
||||
gnutls_pkcs11_obj_list_import_url2 that deinits it up to the correct
|
||||
position.
|
||||
|
||||
With this change, both functions zero unused entries.
|
||||
|
||||
Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
|
||||
Fixes: #1819
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/pkcs11.c | 1 +
|
||||
lib/x509/verify-high2.c | 4 ++--
|
||||
2 files changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/pkcs11.c b/lib/pkcs11.c
|
||||
index d8d4a6511..6a4915f3f 100644
|
||||
--- a/lib/pkcs11.c
|
||||
+++ b/lib/pkcs11.c
|
||||
@@ -3661,6 +3661,7 @@ gnutls_x509_crt_list_import_pkcs11(gnutls_x509_crt_t * certs,
|
||||
cleanup:
|
||||
for (j = 0; j < i; j++) {
|
||||
gnutls_x509_crt_deinit(certs[j]);
|
||||
+ certs[j] = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
diff --git a/lib/x509/verify-high2.c b/lib/x509/verify-high2.c
|
||||
index 9820595e9..9f30a219d 100644
|
||||
--- a/lib/x509/verify-high2.c
|
||||
+++ b/lib/x509/verify-high2.c
|
||||
@@ -216,7 +216,7 @@ int add_trust_list_pkcs11_object_url(gnutls_x509_trust_list_t list, const char *
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
- xcrt_list = gnutls_malloc(sizeof(gnutls_x509_crt_t) * pcrt_list_size);
|
||||
+ xcrt_list = gnutls_calloc(pcrt_list_size, sizeof(gnutls_x509_crt_t));
|
||||
if (xcrt_list == NULL) {
|
||||
ret = GNUTLS_E_MEMORY_ERROR;
|
||||
goto cleanup;
|
||||
@@ -264,7 +264,7 @@ int remove_pkcs11_object_url(gnutls_x509_trust_list_t list, const char *url)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
- xcrt_list = gnutls_malloc(sizeof(gnutls_x509_crt_t) * pcrt_list_size);
|
||||
+ xcrt_list = gnutls_calloc(pcrt_list_size, sizeof(gnutls_x509_crt_t));
|
||||
if (xcrt_list == NULL) {
|
||||
ret = GNUTLS_E_MEMORY_ERROR;
|
||||
goto cleanup;
|
||||
--
|
||||
2.53.0
|
||||
|
||||
488
SOURCES/gnutls-3.6.16-CVE-2026-33845-dtls-uflow.patch
Normal file
488
SOURCES/gnutls-3.6.16-CVE-2026-33845-dtls-uflow.patch
Normal file
@ -0,0 +1,488 @@
|
||||
From bd70e112d4d1f063223f0f0886aaaf33699390d0 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Wed, 22 Apr 2026 14:19:57 +0200
|
||||
Subject: [PATCH 1/5] buffers: rename a variable in parse_handshake_header
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/buffers.c | 20 ++++++++++----------
|
||||
1 file changed, 10 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/lib/buffers.c b/lib/buffers.c
|
||||
index be51f3aac..d9ef1d907 100644
|
||||
--- a/lib/buffers.c
|
||||
+++ b/lib/buffers.c
|
||||
@@ -876,7 +876,7 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
|
||||
{
|
||||
uint8_t *dataptr = NULL; /* for realloc */
|
||||
size_t handshake_header_size =
|
||||
- HANDSHAKE_HEADER_SIZE(session), data_size, frag_size;
|
||||
+ HANDSHAKE_HEADER_SIZE(session), data_size, frag_length;
|
||||
|
||||
/* Note: SSL2_HEADERS == 1 */
|
||||
if (_mbuffer_get_udata_size(bufel) < handshake_header_size)
|
||||
@@ -892,7 +892,7 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
|
||||
&& bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)) {
|
||||
handshake_header_size = SSL2_HEADERS; /* we've already read one byte */
|
||||
|
||||
- frag_size = _mbuffer_get_udata_size(bufel) - handshake_header_size; /* we've read the first byte */
|
||||
+ frag_length = _mbuffer_get_udata_size(bufel) - handshake_header_size; /* we've read the first byte */
|
||||
|
||||
if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO)
|
||||
return
|
||||
@@ -902,7 +902,7 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
|
||||
|
||||
hsk->sequence = 0;
|
||||
hsk->start_offset = 0;
|
||||
- hsk->length = frag_size;
|
||||
+ hsk->length = frag_length;
|
||||
} else
|
||||
#endif
|
||||
{ /* TLS or DTLS handshake headers */
|
||||
@@ -919,12 +919,12 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
|
||||
hsk->sequence = _gnutls_read_uint16(&dataptr[4]);
|
||||
hsk->start_offset =
|
||||
_gnutls_read_uint24(&dataptr[6]);
|
||||
- frag_size =
|
||||
+ frag_length =
|
||||
_gnutls_read_uint24(&dataptr[9]);
|
||||
} else {
|
||||
hsk->sequence = 0;
|
||||
hsk->start_offset = 0;
|
||||
- frag_size =
|
||||
+ frag_length =
|
||||
MIN((_mbuffer_get_udata_size(bufel) -
|
||||
handshake_header_size), hsk->length);
|
||||
}
|
||||
@@ -940,8 +940,8 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
|
||||
}
|
||||
data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;
|
||||
|
||||
- if (frag_size > 0)
|
||||
- hsk->end_offset = hsk->start_offset + frag_size - 1;
|
||||
+ if (frag_length > 0)
|
||||
+ hsk->end_offset = hsk->start_offset + frag_length - 1;
|
||||
else
|
||||
hsk->end_offset = 0;
|
||||
|
||||
@@ -949,15 +949,15 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
|
||||
("HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
|
||||
session, _gnutls_handshake2str(hsk->htype),
|
||||
(unsigned) hsk->htype, (int) hsk->length, (int) data_size,
|
||||
- hsk->start_offset, (int) frag_size,
|
||||
+ hsk->start_offset, (int) frag_length,
|
||||
(int) hsk->sequence);
|
||||
|
||||
hsk->header_size = handshake_header_size;
|
||||
memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel),
|
||||
handshake_header_size);
|
||||
|
||||
- if (hsk->length > 0 && (frag_size > data_size ||
|
||||
- (frag_size > 0 &&
|
||||
+ if (hsk->length > 0 && (frag_length > data_size ||
|
||||
+ (frag_length > 0 &&
|
||||
hsk->end_offset >= hsk->length))) {
|
||||
return
|
||||
gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From e5b72c53c7d789d19d1d1cd10b275e87d0415413 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 23 Mar 2026 15:09:43 +0100
|
||||
Subject: [PATCH 2/5] buffers: switch from end_offset over to frag_length
|
||||
|
||||
Instead of maintaining an inclusive [start_offset, end_offset] range
|
||||
when reassembling DTLS handshake,
|
||||
track start_offset and a relative frag_length instead.
|
||||
|
||||
You'd think it'd be a no-op, but it fixes:
|
||||
|
||||
* 0-length fragments triggering completion if message was 1 byte long
|
||||
* a remotely triggerable underflow and an ensuing heap overrun
|
||||
|
||||
Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
|
||||
Fixes: #1811
|
||||
Fixes: CVE-2026-33845
|
||||
Fixes: GNUTLS-SA-2026-04-29-3
|
||||
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 | 64 +++++++++++++++++++++++++-----------------------
|
||||
lib/gnutls_int.h | 4 +--
|
||||
2 files changed, 36 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/lib/buffers.c b/lib/buffers.c
|
||||
index d9ef1d907..134d680f4 100644
|
||||
--- a/lib/buffers.c
|
||||
+++ b/lib/buffers.c
|
||||
@@ -940,10 +940,7 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
|
||||
}
|
||||
data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;
|
||||
|
||||
- if (frag_length > 0)
|
||||
- hsk->end_offset = hsk->start_offset + frag_length - 1;
|
||||
- else
|
||||
- hsk->end_offset = 0;
|
||||
+ hsk->frag_length = frag_length;
|
||||
|
||||
_gnutls_handshake_log
|
||||
("HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
|
||||
@@ -956,14 +953,16 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
|
||||
memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel),
|
||||
handshake_header_size);
|
||||
|
||||
- if (hsk->length > 0 && (frag_length > data_size ||
|
||||
- (frag_length > 0 &&
|
||||
- hsk->end_offset >= hsk->length))) {
|
||||
+ if (hsk->length > 0 &&
|
||||
+ (frag_length > data_size ||
|
||||
+ (frag_length > 0 &&
|
||||
+ hsk->start_offset + frag_length > hsk->length))) {
|
||||
return
|
||||
gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
||||
}
|
||||
- else if (hsk->length == 0 && hsk->end_offset != 0
|
||||
- && hsk->start_offset != 0)
|
||||
+ else if (hsk->length == 0 &&
|
||||
+ hsk->start_offset + frag_length != hsk->start_offset &&
|
||||
+ hsk->start_offset != 0)
|
||||
return
|
||||
gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
||||
|
||||
@@ -1020,19 +1019,19 @@ static int merge_handshake_packet(gnutls_session_t session,
|
||||
gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
|
||||
|
||||
if (!exists) {
|
||||
- if (hsk->length > 0 && hsk->end_offset > 0
|
||||
- && hsk->end_offset - hsk->start_offset + 1 !=
|
||||
- hsk->length) {
|
||||
+ if (hsk->length > 0) {
|
||||
ret =
|
||||
_gnutls_buffer_resize(&hsk->data, hsk->length);
|
||||
if (ret < 0)
|
||||
return gnutls_assert_val(ret);
|
||||
|
||||
hsk->data.length = hsk->length;
|
||||
+ }
|
||||
|
||||
+ if (hsk->length > 0 && hsk->frag_length > 0 &&
|
||||
+ hsk->frag_length != hsk->length) {
|
||||
memmove(&hsk->data.data[hsk->start_offset],
|
||||
- hsk->data.data,
|
||||
- hsk->end_offset - hsk->start_offset + 1);
|
||||
+ hsk->data.data, hsk->frag_length);
|
||||
}
|
||||
|
||||
session->internals.handshake_recv_buffer_size++;
|
||||
@@ -1066,20 +1065,27 @@ static int merge_handshake_packet(gnutls_session_t session,
|
||||
}
|
||||
|
||||
if (hsk->start_offset < recv_buf[pos].start_offset &&
|
||||
- hsk->end_offset + 1 >= recv_buf[pos].start_offset) {
|
||||
+ hsk->start_offset + hsk->frag_length >=
|
||||
+ recv_buf[pos].start_offset) {
|
||||
memcpy(&recv_buf[pos].data.data[hsk->start_offset],
|
||||
hsk->data.data, hsk->data.length);
|
||||
recv_buf[pos].start_offset = hsk->start_offset;
|
||||
- recv_buf[pos].end_offset =
|
||||
- MIN(hsk->end_offset, recv_buf[pos].end_offset);
|
||||
- } else if (hsk->end_offset > recv_buf[pos].end_offset &&
|
||||
- hsk->start_offset <= recv_buf[pos].end_offset + 1) {
|
||||
+ recv_buf[pos].frag_length = MIN(
|
||||
+ hsk->frag_length, recv_buf[pos].frag_length);
|
||||
+ } else if (hsk->start_offset + hsk->frag_length >
|
||||
+ recv_buf[pos].start_offset +
|
||||
+ recv_buf[pos].frag_length &&
|
||||
+ hsk->start_offset <=
|
||||
+ recv_buf[pos].start_offset +
|
||||
+ recv_buf[pos].frag_length) {
|
||||
memcpy(&recv_buf[pos].data.data[hsk->start_offset],
|
||||
hsk->data.data, hsk->data.length);
|
||||
|
||||
- recv_buf[pos].end_offset = hsk->end_offset;
|
||||
recv_buf[pos].start_offset = MIN(
|
||||
hsk->start_offset, recv_buf[pos].start_offset);
|
||||
+ recv_buf[pos].frag_length = hsk->start_offset +
|
||||
+ hsk->frag_length -
|
||||
+ recv_buf[pos].start_offset;
|
||||
}
|
||||
_gnutls_handshake_buffer_clear(hsk);
|
||||
}
|
||||
@@ -1140,8 +1146,8 @@ static int get_last_packet(gnutls_session_t session,
|
||||
}
|
||||
|
||||
else if ((recv_buf[LAST_ELEMENT].start_offset == 0 &&
|
||||
- recv_buf[LAST_ELEMENT].end_offset ==
|
||||
- recv_buf[LAST_ELEMENT].length - 1)
|
||||
+ recv_buf[LAST_ELEMENT].frag_length ==
|
||||
+ recv_buf[LAST_ELEMENT].length)
|
||||
|| recv_buf[LAST_ELEMENT].length == 0) {
|
||||
session->internals.dtls.hsk_read_seq++;
|
||||
_gnutls_handshake_buffer_move(hsk,
|
||||
@@ -1153,7 +1159,9 @@ static int get_last_packet(gnutls_session_t session,
|
||||
/* if we don't have a complete handshake message, but we
|
||||
* have queued data waiting, try again to reconstruct the
|
||||
* handshake packet, using the queued */
|
||||
- if (recv_buf[LAST_ELEMENT].end_offset != recv_buf[LAST_ELEMENT].length - 1 &&
|
||||
+ if ((recv_buf[LAST_ELEMENT].start_offset +
|
||||
+ recv_buf[LAST_ELEMENT].frag_length) !=
|
||||
+ recv_buf[LAST_ELEMENT].length &&
|
||||
record_check_unprocessed(session) > 0)
|
||||
return gnutls_assert_val(GNUTLS_E_INT_CHECK_AGAIN);
|
||||
else
|
||||
@@ -1341,9 +1349,7 @@ int _gnutls_parse_record_buffered_msgs(gnutls_session_t session)
|
||||
ret);
|
||||
|
||||
data_size =
|
||||
- MIN(tmp.length,
|
||||
- tmp.end_offset - tmp.start_offset +
|
||||
- 1);
|
||||
+ MIN(tmp.length, tmp.frag_length);
|
||||
|
||||
ret =
|
||||
_gnutls_buffer_append_data(&tmp.data,
|
||||
@@ -1361,9 +1367,7 @@ int _gnutls_parse_record_buffered_msgs(gnutls_session_t session)
|
||||
merge_handshake_packet(session, &tmp);
|
||||
if (ret < 0)
|
||||
return gnutls_assert_val(ret);
|
||||
-
|
||||
- }
|
||||
- while (_mbuffer_get_udata_size(bufel) > 0);
|
||||
+ } while (_mbuffer_get_udata_size(bufel) > 0);
|
||||
|
||||
prev = bufel;
|
||||
bufel =
|
||||
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
|
||||
index 815f69b10..0e753a739 100644
|
||||
--- a/lib/gnutls_int.h
|
||||
+++ b/lib/gnutls_int.h
|
||||
@@ -396,10 +396,10 @@ typedef struct {
|
||||
uint16_t sequence;
|
||||
|
||||
/* indicate whether that message is complete.
|
||||
- * complete means start_offset == 0 and end_offset == length
|
||||
+ * complete means start_offset == 0 and frag_length == length
|
||||
*/
|
||||
uint32_t start_offset;
|
||||
- uint32_t end_offset;
|
||||
+ uint32_t frag_length; /* used exclusively in DTLS reassembly */
|
||||
|
||||
uint8_t header[MAX_HANDSHAKE_HEADER_SIZE];
|
||||
int header_size;
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 21563d8778dfec2d87d415d7e7f7ba3b66f1d283 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 23 Mar 2026 15:57:39 +0100
|
||||
Subject: [PATCH 3/5] buffers: simplify and tighten parse_handshake_header
|
||||
checks
|
||||
|
||||
* frag_size > data_size is now rejected even when length == 0
|
||||
* length == 0 && frag_size > 0 is now rejected even when start_offset == 0
|
||||
* start_offset > length is now rejected even when frag_size == 0
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/buffers.c | 10 ++--------
|
||||
1 file changed, 2 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/lib/buffers.c b/lib/buffers.c
|
||||
index 134d680f4..7aa22811f 100644
|
||||
--- a/lib/buffers.c
|
||||
+++ b/lib/buffers.c
|
||||
@@ -953,16 +953,10 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
|
||||
memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel),
|
||||
handshake_header_size);
|
||||
|
||||
- if (hsk->length > 0 &&
|
||||
- (frag_length > data_size ||
|
||||
- (frag_length > 0 &&
|
||||
- hsk->start_offset + frag_length > hsk->length))) {
|
||||
+ if (frag_length > data_size) /* fragment straight up lying to us */
|
||||
return
|
||||
gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
||||
- }
|
||||
- else if (hsk->length == 0 &&
|
||||
- hsk->start_offset + frag_length != hsk->start_offset &&
|
||||
- hsk->start_offset != 0)
|
||||
+ if (frag_length + hsk->start_offset > hsk->length) /* reassembly OOB */
|
||||
return
|
||||
gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 1057846cd5c611037113327f5ae38af2c5cd7c87 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Fri, 20 Mar 2026 16:55:10 +0100
|
||||
Subject: [PATCH 4/5] tests/mini-dtls-fragments: test injecting 0-length ones
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/mini-dtls-fragments.c | 47 +++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 47 insertions(+)
|
||||
|
||||
diff --git a/tests/mini-dtls-fragments.c b/tests/mini-dtls-fragments.c
|
||||
index 4f4c8f623..5d226a56a 100644
|
||||
--- a/tests/mini-dtls-fragments.c
|
||||
+++ b/tests/mini-dtls-fragments.c
|
||||
@@ -165,6 +165,50 @@ static uint64_t read_u48(const uint8_t *p)
|
||||
return seq;
|
||||
}
|
||||
|
||||
+static void make_0frag(uint8_t *dst, const uint8_t *src)
|
||||
+{
|
||||
+ memcpy(dst, src, 13 + 12);
|
||||
+ dst[13 + 6] = dst[13 + 7] = dst[13 + 8] = 0; /* frag offset = 0 */
|
||||
+ dst[13 + 9] = dst[13 + 10] = dst[13 + 11] = 0; /* frag length = 0 */
|
||||
+ /* record payload length: just the 12-byte handshake header, no data */
|
||||
+ dst[11] = 0;
|
||||
+ dst[12] = 12;
|
||||
+}
|
||||
+
|
||||
+ATTRIBUTE_NONNULL((2))
|
||||
+static ssize_t client_push_inj0(gnutls_transport_ptr_t tr, const void *d_,
|
||||
+ size_t l)
|
||||
+{
|
||||
+ static uint32_t seq = 0;
|
||||
+ const uint8_t *d = (const uint8_t *)d_;
|
||||
+ uint8_t frag[13 + 12];
|
||||
+ uint8_t *b;
|
||||
+
|
||||
+ if (l < 13) /* too short for a DTLS record header */
|
||||
+ return queue_put(&c2s, d, l);
|
||||
+ if (!(d[3] == 0 && d[4] == 0)) /* not epoch 0: encrypted, don't touch */
|
||||
+ return queue_put(&c2s, d, l);
|
||||
+
|
||||
+ b = malloc(l);
|
||||
+ assert(b);
|
||||
+ memcpy(b, d, l);
|
||||
+
|
||||
+ if (l >= 13 + 12 && d[0] == 22) { /* handshake record: inject 0-frag */
|
||||
+ make_0frag(frag, d);
|
||||
+ write_u48(frag + 5, seq++); /* 0-frag first */
|
||||
+ queue_put(&c2s, frag, sizeof(frag));
|
||||
+
|
||||
+ write_u48(b + 5, seq++); /* real second */
|
||||
+ queue_put(&c2s, b, l);
|
||||
+ } else { /* other (e.g. CCS): just renumber */
|
||||
+ write_u48(b + 5, seq++);
|
||||
+ queue_put(&c2s, b, l);
|
||||
+ }
|
||||
+
|
||||
+ free(b);
|
||||
+ return l;
|
||||
+}
|
||||
+
|
||||
static void test(gnutls_push_func client_push, bool expect_success)
|
||||
{
|
||||
gnutls_session_t client, server;
|
||||
@@ -459,7 +503,10 @@ static ssize_t client_push_split_hello_bad_seq(gnutls_transport_ptr_t tr,
|
||||
void doit(void)
|
||||
{
|
||||
global_init();
|
||||
+ success("normal:\n");
|
||||
test(client_push_normal, true);
|
||||
+ success("valid 0-len fragments injected every 2nd push in epoch0:\n");
|
||||
+ test(client_push_inj0, true);
|
||||
success("malicious reassembly bug exploitation (#1816):\n");
|
||||
test_malicious1816();
|
||||
success("split client hello smoke-test\n");
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From d59d9cc7943568ee06e5ba35fd7ae2a6e433059f Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 23 Mar 2026 20:24:26 +0100
|
||||
Subject: [PATCH 5/5] tests/mini-dtls-fragments: test #1811 crashing datagram
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/mini-dtls-fragments.c | 58 +++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 58 insertions(+)
|
||||
|
||||
diff --git a/tests/mini-dtls-fragments.c b/tests/mini-dtls-fragments.c
|
||||
index 5d226a56a..03881058a 100644
|
||||
--- a/tests/mini-dtls-fragments.c
|
||||
+++ b/tests/mini-dtls-fragments.c
|
||||
@@ -500,6 +500,62 @@ static ssize_t client_push_split_hello_bad_seq(gnutls_transport_ptr_t tr,
|
||||
return l;
|
||||
}
|
||||
|
||||
+static void test_malicious1811(void)
|
||||
+{
|
||||
+ static const uint8_t dgram[] = {
|
||||
+ 22, /* type = handshake */
|
||||
+ 0xfe, 0xfd, /* version = DTLS 1.2 */
|
||||
+ 0x00, 0x00, /* epoch = 0 */
|
||||
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* seq = 0 */
|
||||
+ 0x00, 0x0c, /* record length = 12 */
|
||||
+
|
||||
+ 0x01, /* type = ClientHello */
|
||||
+ 0xff, 0xff, 0xff, /* length = 0xffffff (!) */
|
||||
+ 0x00, 0x00, /* msg seq = 0 */
|
||||
+ 0x00, 0x00, 0x02, /* frag_offset = 2 (!) */
|
||||
+ 0x00, 0x00, 0x00, /* frag_length = 0 (!) */
|
||||
+ };
|
||||
+ gnutls_session_t server;
|
||||
+ gnutls_certificate_credentials_t scred;
|
||||
+ int sr;
|
||||
+
|
||||
+ if (debug)
|
||||
+ gnutls_global_set_log_level(4711);
|
||||
+
|
||||
+ gnutls_certificate_allocate_credentials(&scred);
|
||||
+ gnutls_certificate_set_x509_key_mem(scred, &server_cert, &server_key,
|
||||
+ GNUTLS_X509_FMT_PEM);
|
||||
+
|
||||
+ gnutls_init(&server, GNUTLS_SERVER | GNUTLS_DATAGRAM);
|
||||
+ gnutls_priority_set_direct(server, "NORMAL:+VERS-DTLS1.2", NULL);
|
||||
+ gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, scred);
|
||||
+
|
||||
+ gnutls_dtls_set_timeouts(server, 80 * 1000, 8 * 1000);
|
||||
+
|
||||
+ gnutls_transport_set_ptr(server, server);
|
||||
+ gnutls_transport_set_push_function(server, server_push);
|
||||
+ gnutls_transport_set_pull_function(server, server_pull);
|
||||
+ gnutls_transport_set_pull_timeout_function(server,
|
||||
+ c2s_pull_timeout_once);
|
||||
+
|
||||
+ queue_put(&c2s, dgram, sizeof(dgram));
|
||||
+
|
||||
+ gnutls_global_set_log_function(server_log_func);
|
||||
+ do {
|
||||
+ sr = gnutls_handshake(server); /* crashes if vulnerable */
|
||||
+ } while (c2s.head != c2s.tail && !gnutls_error_is_fatal(sr));
|
||||
+ if (gnutls_error_is_fatal(sr))
|
||||
+ fail("server: %s\n", gnutls_strerror(sr));
|
||||
+
|
||||
+ success("OK\n");
|
||||
+
|
||||
+ queue_reset(&c2s);
|
||||
+ queue_reset(&s2c);
|
||||
+
|
||||
+ gnutls_deinit(server);
|
||||
+ gnutls_certificate_free_credentials(scred);
|
||||
+}
|
||||
+
|
||||
void doit(void)
|
||||
{
|
||||
global_init();
|
||||
@@ -513,6 +569,8 @@ void doit(void)
|
||||
test(client_push_split_hello, true);
|
||||
success("split client hello smoke-test and mangle sequence number\n");
|
||||
test(client_push_split_hello_bad_seq, false);
|
||||
+ success("malicious injection aiming for an underflow (#1811):\n");
|
||||
+ test_malicious1811();
|
||||
gnutls_global_deinit();
|
||||
}
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
944
SOURCES/gnutls-3.6.16-CVE-2026-33846-dtls-len.patch
Normal file
944
SOURCES/gnutls-3.6.16-CVE-2026-33846-dtls-len.patch
Normal file
@ -0,0 +1,944 @@
|
||||
From 4f94e5cfe1f252a431e41642b0752e7e0daf43b9 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Fri, 20 Mar 2026 16:09:40 +0100
|
||||
Subject: [PATCH 1/8] tests/mini-dtls-fragments: implement a basic DTLS test
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/Makefile.am | 6 +-
|
||||
tests/mini-dtls-fragments.c | 206 ++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 211 insertions(+), 1 deletion(-)
|
||||
create mode 100644 tests/mini-dtls-fragments.c
|
||||
|
||||
diff --git a/tests/Makefile.am b/tests/Makefile.am
|
||||
index afb665597..f85a6947d 100644
|
||||
--- a/tests/Makefile.am
|
||||
+++ b/tests/Makefile.am
|
||||
@@ -224,7 +224,7 @@ ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniquei
|
||||
set_x509_ocsp_multi_cli kdf-api keylog-func \
|
||||
dtls_hello_random_value tls_hello_random_value x509cert-dntypes \
|
||||
pkcs7-verify-double-free \
|
||||
- tls12-rehandshake-ticket
|
||||
+ tls12-rehandshake-ticket mini-dtls-fragments
|
||||
|
||||
if HAVE_SECCOMP_TESTS
|
||||
ctests += dtls-with-seccomp tls-with-seccomp dtls-client-with-seccomp tls-client-with-seccomp
|
||||
@@ -487,6 +487,10 @@ buffer_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||
-I$(top_srcdir)/gl \
|
||||
-I$(top_builddir)/gl
|
||||
|
||||
+mini_dtls_fragments_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||
+ -I$(top_srcdir)/gl \
|
||||
+ -I$(top_builddir)/gl
|
||||
+
|
||||
if ENABLE_PKCS11
|
||||
if !WINDOWS
|
||||
ctests += tls13/post-handshake-with-cert-pkcs11 pkcs11/tls-neg-pkcs11-no-key \
|
||||
diff --git a/tests/mini-dtls-fragments.c b/tests/mini-dtls-fragments.c
|
||||
new file mode 100644
|
||||
index 000000000..0abe557f7
|
||||
--- /dev/null
|
||||
+++ b/tests/mini-dtls-fragments.c
|
||||
@@ -0,0 +1,206 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2026 Red Hat, Inc.
|
||||
+ *
|
||||
+ * Author: Alexander Sosedkin
|
||||
+ *
|
||||
+ * This file is part of GnuTLS.
|
||||
+ *
|
||||
+ * GnuTLS is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation; either version 3 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * GnuTLS is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU Lesser General Public License
|
||||
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
+ */
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+#include "config.h"
|
||||
+#endif
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+
|
||||
+#if defined(_WIN32)
|
||||
+
|
||||
+int main(void)
|
||||
+{
|
||||
+ exit(77);
|
||||
+}
|
||||
+
|
||||
+#else
|
||||
+
|
||||
+#include <assert.h>
|
||||
+#include <errno.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <stdint.h>
|
||||
+#include <string.h>
|
||||
+#include <gnutls/gnutls.h>
|
||||
+#include <gnutls/dtls.h>
|
||||
+#include "cert-common.h"
|
||||
+#include "utils.h"
|
||||
+
|
||||
+#include "attribute.h"
|
||||
+
|
||||
+static void server_log_func(int level, const char *str)
|
||||
+{
|
||||
+ fprintf(stderr, "server|<%d>| %s", level, str);
|
||||
+}
|
||||
+
|
||||
+static void client_log_func(int level, const char *str)
|
||||
+{
|
||||
+ fprintf(stderr, "client|<%d>| %s", level, str);
|
||||
+}
|
||||
+
|
||||
+#define QUEUE_SIZE 1024
|
||||
+#define PACKET_SIZE 2048
|
||||
+
|
||||
+typedef struct {
|
||||
+ uint8_t buf[PACKET_SIZE];
|
||||
+ size_t len;
|
||||
+} packet_t;
|
||||
+typedef struct {
|
||||
+ packet_t packets[QUEUE_SIZE];
|
||||
+ size_t head;
|
||||
+ size_t tail;
|
||||
+} queue_t;
|
||||
+
|
||||
+static queue_t c2s, s2c;
|
||||
+
|
||||
+static int queue_put(queue_t *q, const void *buf, size_t len)
|
||||
+{
|
||||
+ assert(len <= PACKET_SIZE);
|
||||
+ memcpy(q->packets[q->tail].buf, buf, len);
|
||||
+ q->packets[q->tail].len = len;
|
||||
+ q->tail++;
|
||||
+ q->tail %= QUEUE_SIZE;
|
||||
+ assert(q->tail != q->head);
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
+static ssize_t queue_get(queue_t *q, gnutls_session_t s, void *buf, size_t len)
|
||||
+{
|
||||
+ if (q->head == q->tail) {
|
||||
+ gnutls_transport_set_errno(s, EAGAIN);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ size_t n = q->packets[q->head].len;
|
||||
+ memcpy(buf, q->packets[q->head].buf, n);
|
||||
+ q->head++;
|
||||
+ q->head %= QUEUE_SIZE;
|
||||
+ return n;
|
||||
+}
|
||||
+
|
||||
+static void queue_reset(queue_t *q)
|
||||
+{
|
||||
+ q->head = q->tail = 0;
|
||||
+}
|
||||
+
|
||||
+static int pull_timeout(gnutls_transport_ptr_t tr, unsigned ms)
|
||||
+{
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static ssize_t server_pull(gnutls_transport_ptr_t tr, void *b, size_t l)
|
||||
+{
|
||||
+ return queue_get(&c2s, (gnutls_session_t)tr, b, l);
|
||||
+}
|
||||
+
|
||||
+static ssize_t client_pull(gnutls_transport_ptr_t tr, void *b, size_t l)
|
||||
+{
|
||||
+ return queue_get(&s2c, (gnutls_session_t)tr, b, l);
|
||||
+}
|
||||
+
|
||||
+static ssize_t server_push(gnutls_transport_ptr_t tr, const void *b, size_t l)
|
||||
+{
|
||||
+ return queue_put(&s2c, b, l);
|
||||
+}
|
||||
+
|
||||
+static ssize_t client_push_normal(gnutls_transport_ptr_t tr, const void *b,
|
||||
+ size_t l)
|
||||
+{
|
||||
+ return queue_put(&c2s, b, l);
|
||||
+}
|
||||
+
|
||||
+static void test(gnutls_push_func client_push)
|
||||
+{
|
||||
+ gnutls_session_t client, server;
|
||||
+ gnutls_certificate_credentials_t ccred, scred;
|
||||
+ int cr = 0, sr = 0;
|
||||
+ bool cdone = false, sdone = false;
|
||||
+
|
||||
+ if (debug)
|
||||
+ gnutls_global_set_log_level(4711);
|
||||
+
|
||||
+ gnutls_certificate_allocate_credentials(&scred);
|
||||
+ gnutls_certificate_set_x509_key_mem(scred, &server_cert, &server_key,
|
||||
+ GNUTLS_X509_FMT_PEM);
|
||||
+ gnutls_certificate_allocate_credentials(&ccred);
|
||||
+
|
||||
+ gnutls_init(&server, GNUTLS_SERVER | GNUTLS_DATAGRAM);
|
||||
+ gnutls_init(&client, GNUTLS_CLIENT | GNUTLS_DATAGRAM);
|
||||
+
|
||||
+ gnutls_priority_set_direct(server, "NORMAL:-VERS-ALL:+VERS-DTLS1.2",
|
||||
+ NULL);
|
||||
+ gnutls_priority_set_direct(client, "NORMAL:-VERS-ALL:+VERS-DTLS1.2",
|
||||
+ NULL);
|
||||
+
|
||||
+ gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, scred);
|
||||
+ gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, ccred);
|
||||
+
|
||||
+ gnutls_dtls_set_timeouts(client, 80 * 1000, 8 * 1000);
|
||||
+ gnutls_dtls_set_timeouts(server, 80 * 1000, 8 * 1000);
|
||||
+
|
||||
+ gnutls_transport_set_ptr(client, client);
|
||||
+ gnutls_transport_set_push_function(client, client_push);
|
||||
+ gnutls_transport_set_pull_function(client, client_pull);
|
||||
+ gnutls_transport_set_pull_timeout_function(client, pull_timeout);
|
||||
+
|
||||
+ gnutls_transport_set_ptr(server, server);
|
||||
+ gnutls_transport_set_push_function(server, server_push);
|
||||
+ gnutls_transport_set_pull_function(server, server_pull);
|
||||
+ gnutls_transport_set_pull_timeout_function(server, pull_timeout);
|
||||
+
|
||||
+ while (!cdone || !sdone) {
|
||||
+ gnutls_global_set_log_function(client_log_func);
|
||||
+ if (!cdone)
|
||||
+ cr = gnutls_handshake(client);
|
||||
+ if (!cr || gnutls_error_is_fatal(cr))
|
||||
+ cdone = true;
|
||||
+
|
||||
+ gnutls_global_set_log_function(server_log_func);
|
||||
+ if (!sdone)
|
||||
+ sr = gnutls_handshake(server);
|
||||
+ if (!sr || gnutls_error_is_fatal(sr))
|
||||
+ sdone = true;
|
||||
+ }
|
||||
+
|
||||
+ if (cr)
|
||||
+ fail("client: %s\n", gnutls_strerror(cr));
|
||||
+ if (sr)
|
||||
+ fail("server: %s\n", gnutls_strerror(sr));
|
||||
+
|
||||
+ success("OK\n");
|
||||
+
|
||||
+ queue_reset(&c2s);
|
||||
+ queue_reset(&s2c);
|
||||
+
|
||||
+ gnutls_deinit(client);
|
||||
+ gnutls_deinit(server);
|
||||
+ gnutls_certificate_free_credentials(ccred);
|
||||
+ gnutls_certificate_free_credentials(scred);
|
||||
+}
|
||||
+
|
||||
+void doit(void)
|
||||
+{
|
||||
+ global_init();
|
||||
+ test(client_push_normal);
|
||||
+ gnutls_global_deinit();
|
||||
+}
|
||||
+
|
||||
+#endif /* _WIN32 */
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 87b63fec37a9bae87ec34f6a55c57cb64fe4c7aa Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 4 May 2026 09:16:13 +0000
|
||||
Subject: [PATCH 2/8] buffers: reformat ssmerge_handshake_packet
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
|
||||
---
|
||||
lib/buffers.c | 64 +++++++++++++++++++++++++--------------------------
|
||||
1 file changed, 31 insertions(+), 33 deletions(-)
|
||||
|
||||
diff --git a/lib/buffers.c b/lib/buffers.c
|
||||
index 2d0e3d8af..827e97fe5 100644
|
||||
--- a/lib/buffers.c
|
||||
+++ b/lib/buffers.c
|
||||
@@ -1031,46 +1031,44 @@ static int merge_handshake_packet(gnutls_session_t session,
|
||||
_gnutls_write_uint24(0, &hsk->header[6]);
|
||||
_gnutls_write_uint24(hsk->length, &hsk->header[9]);
|
||||
|
||||
- _gnutls_handshake_buffer_move(&session->internals.
|
||||
- handshake_recv_buffer[pos],
|
||||
- hsk);
|
||||
+ _gnutls_handshake_buffer_move(
|
||||
+ &session->internals.handshake_recv_buffer[pos], hsk);
|
||||
|
||||
} else {
|
||||
if (hsk->start_offset <
|
||||
- session->internals.handshake_recv_buffer[pos].
|
||||
- start_offset
|
||||
- && hsk->end_offset + 1 >=
|
||||
- session->internals.handshake_recv_buffer[pos].
|
||||
- start_offset) {
|
||||
- memcpy(&session->internals.
|
||||
- handshake_recv_buffer[pos].data.data[hsk->
|
||||
- start_offset],
|
||||
+ session->internals.handshake_recv_buffer[pos]
|
||||
+ .start_offset &&
|
||||
+ hsk->end_offset + 1 >=
|
||||
+ session->internals.handshake_recv_buffer[pos]
|
||||
+ .start_offset) {
|
||||
+ memcpy(&session->internals.handshake_recv_buffer[pos]
|
||||
+ .data.data[hsk->start_offset],
|
||||
hsk->data.data, hsk->data.length);
|
||||
- session->internals.handshake_recv_buffer[pos].
|
||||
- start_offset = hsk->start_offset;
|
||||
- session->internals.handshake_recv_buffer[pos].
|
||||
- end_offset =
|
||||
- MIN(hsk->end_offset,
|
||||
- session->internals.
|
||||
- handshake_recv_buffer[pos].end_offset);
|
||||
+ session->internals.handshake_recv_buffer[pos]
|
||||
+ .start_offset = hsk->start_offset;
|
||||
+ session->internals.handshake_recv_buffer[pos]
|
||||
+ .end_offset = MIN(
|
||||
+ hsk->end_offset,
|
||||
+ session->internals.handshake_recv_buffer[pos]
|
||||
+ .end_offset);
|
||||
} else if (hsk->end_offset >
|
||||
- session->internals.handshake_recv_buffer[pos].
|
||||
- end_offset
|
||||
- && hsk->start_offset <=
|
||||
- session->internals.handshake_recv_buffer[pos].
|
||||
- end_offset + 1) {
|
||||
- memcpy(&session->internals.
|
||||
- handshake_recv_buffer[pos].data.data[hsk->
|
||||
- start_offset],
|
||||
+ session->internals.handshake_recv_buffer[pos]
|
||||
+ .end_offset &&
|
||||
+ hsk->start_offset <=
|
||||
+ session->internals.handshake_recv_buffer[pos]
|
||||
+ .end_offset +
|
||||
+ 1) {
|
||||
+ memcpy(&session->internals.handshake_recv_buffer[pos]
|
||||
+ .data.data[hsk->start_offset],
|
||||
hsk->data.data, hsk->data.length);
|
||||
|
||||
- session->internals.handshake_recv_buffer[pos].
|
||||
- end_offset = hsk->end_offset;
|
||||
- session->internals.handshake_recv_buffer[pos].
|
||||
- start_offset =
|
||||
- MIN(hsk->start_offset,
|
||||
- session->internals.
|
||||
- handshake_recv_buffer[pos].start_offset);
|
||||
+ session->internals.handshake_recv_buffer[pos]
|
||||
+ .end_offset = hsk->end_offset;
|
||||
+ session->internals.handshake_recv_buffer[pos]
|
||||
+ .start_offset = MIN(
|
||||
+ hsk->start_offset,
|
||||
+ session->internals.handshake_recv_buffer[pos]
|
||||
+ .start_offset);
|
||||
}
|
||||
_gnutls_handshake_buffer_clear(hsk);
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 9deffca528c23bbb218f5ec3bd4bb1bf4cbd1fc0 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Fri, 17 Apr 2026 17:49:31 +0200
|
||||
Subject: [PATCH 3/8] buffers: shorten merge_handshake_packet using recv_buf
|
||||
|
||||
I had vague concerns about thread-safety of this,
|
||||
but then this pattern already exists within the file.
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/buffers.c | 52 +++++++++++++++++----------------------------------
|
||||
1 file changed, 17 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/lib/buffers.c b/lib/buffers.c
|
||||
index 827e97fe5..9ff606501 100644
|
||||
--- a/lib/buffers.c
|
||||
+++ b/lib/buffers.c
|
||||
@@ -992,9 +992,11 @@ static int merge_handshake_packet(gnutls_session_t session,
|
||||
int exists = 0, i, pos = 0;
|
||||
int ret;
|
||||
|
||||
+ handshake_buffer_st *recv_buf =
|
||||
+ session->internals.handshake_recv_buffer;
|
||||
+
|
||||
for (i = 0; i < session->internals.handshake_recv_buffer_size; i++) {
|
||||
- if (session->internals.handshake_recv_buffer[i].htype ==
|
||||
- hsk->htype) {
|
||||
+ if (recv_buf[i].htype == hsk->htype) {
|
||||
exists = 1;
|
||||
pos = i;
|
||||
break;
|
||||
@@ -1031,44 +1033,24 @@ static int merge_handshake_packet(gnutls_session_t session,
|
||||
_gnutls_write_uint24(0, &hsk->header[6]);
|
||||
_gnutls_write_uint24(hsk->length, &hsk->header[9]);
|
||||
|
||||
- _gnutls_handshake_buffer_move(
|
||||
- &session->internals.handshake_recv_buffer[pos], hsk);
|
||||
+ _gnutls_handshake_buffer_move(&recv_buf[pos], hsk);
|
||||
|
||||
} else {
|
||||
- if (hsk->start_offset <
|
||||
- session->internals.handshake_recv_buffer[pos]
|
||||
- .start_offset &&
|
||||
- hsk->end_offset + 1 >=
|
||||
- session->internals.handshake_recv_buffer[pos]
|
||||
- .start_offset) {
|
||||
- memcpy(&session->internals.handshake_recv_buffer[pos]
|
||||
- .data.data[hsk->start_offset],
|
||||
+ if (hsk->start_offset < recv_buf[pos].start_offset &&
|
||||
+ hsk->end_offset + 1 >= recv_buf[pos].start_offset) {
|
||||
+ memcpy(&recv_buf[pos].data.data[hsk->start_offset],
|
||||
hsk->data.data, hsk->data.length);
|
||||
- session->internals.handshake_recv_buffer[pos]
|
||||
- .start_offset = hsk->start_offset;
|
||||
- session->internals.handshake_recv_buffer[pos]
|
||||
- .end_offset = MIN(
|
||||
- hsk->end_offset,
|
||||
- session->internals.handshake_recv_buffer[pos]
|
||||
- .end_offset);
|
||||
- } else if (hsk->end_offset >
|
||||
- session->internals.handshake_recv_buffer[pos]
|
||||
- .end_offset &&
|
||||
- hsk->start_offset <=
|
||||
- session->internals.handshake_recv_buffer[pos]
|
||||
- .end_offset +
|
||||
- 1) {
|
||||
- memcpy(&session->internals.handshake_recv_buffer[pos]
|
||||
- .data.data[hsk->start_offset],
|
||||
+ recv_buf[pos].start_offset = hsk->start_offset;
|
||||
+ recv_buf[pos].end_offset =
|
||||
+ MIN(hsk->end_offset, recv_buf[pos].end_offset);
|
||||
+ } else if (hsk->end_offset > recv_buf[pos].end_offset &&
|
||||
+ hsk->start_offset <= recv_buf[pos].end_offset + 1) {
|
||||
+ memcpy(&recv_buf[pos].data.data[hsk->start_offset],
|
||||
hsk->data.data, hsk->data.length);
|
||||
|
||||
- session->internals.handshake_recv_buffer[pos]
|
||||
- .end_offset = hsk->end_offset;
|
||||
- session->internals.handshake_recv_buffer[pos]
|
||||
- .start_offset = MIN(
|
||||
- hsk->start_offset,
|
||||
- session->internals.handshake_recv_buffer[pos]
|
||||
- .start_offset);
|
||||
+ recv_buf[pos].end_offset = hsk->end_offset;
|
||||
+ recv_buf[pos].start_offset = MIN(
|
||||
+ hsk->start_offset, recv_buf[pos].start_offset);
|
||||
}
|
||||
_gnutls_handshake_buffer_clear(hsk);
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 65ab33fa54e34fba69d793735b7df3d383d1ff78 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Fri, 17 Apr 2026 18:21:36 +0200
|
||||
Subject: [PATCH 4/8] buffers: add more checks to DTLS reassembly
|
||||
|
||||
Previously, gnutls didn't check that DTLS fragments claimed
|
||||
a consistent message_length value.
|
||||
Additionally, a crucial array size check was missing,
|
||||
enabling an attacker to cause a heap overwrite.
|
||||
The updated version rejects fragments with mismatching length
|
||||
and adds a missing boundary check.
|
||||
|
||||
Reported-by: Haruto Kimura (Stella)
|
||||
Reported-by: Oscar Reparaz
|
||||
Reported-by: Zou Dikai
|
||||
Fixes: #1816
|
||||
Fixes: #1838
|
||||
Fixes: #1839
|
||||
Fixes: CVE-2026-33846
|
||||
Fixes: GNUTLS-SA-2026-04-29-1
|
||||
CVSS: 7.4 High CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:H
|
||||
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 | 20 ++++++++++++++++++++
|
||||
1 file changed, 20 insertions(+)
|
||||
|
||||
diff --git a/lib/buffers.c b/lib/buffers.c
|
||||
index 9ff606501..20ff909bd 100644
|
||||
--- a/lib/buffers.c
|
||||
+++ b/lib/buffers.c
|
||||
@@ -1036,6 +1036,26 @@ static int merge_handshake_packet(gnutls_session_t session,
|
||||
_gnutls_handshake_buffer_move(&recv_buf[pos], hsk);
|
||||
|
||||
} else {
|
||||
+ if (hsk->length != recv_buf[pos].length) {
|
||||
+ /* inconsistent across fragments */
|
||||
+ _gnutls_handshake_buffer_clear(hsk);
|
||||
+ return gnutls_assert_val(
|
||||
+ GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
||||
+ }
|
||||
+ /* start_offset + data.length <= hsk->length <= max_length */
|
||||
+ if (hsk->length < hsk->start_offset + hsk->data.length) {
|
||||
+ /* impossible claims, overflow requested */
|
||||
+ _gnutls_handshake_buffer_clear(hsk);
|
||||
+ return gnutls_assert_val(
|
||||
+ GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
||||
+ }
|
||||
+ if (hsk->length > recv_buf[pos].data.max_length) {
|
||||
+ /* we don't have this much allocated, overflow guard */
|
||||
+ _gnutls_handshake_buffer_clear(hsk);
|
||||
+ return gnutls_assert_val(
|
||||
+ GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
|
||||
+ }
|
||||
+
|
||||
if (hsk->start_offset < recv_buf[pos].start_offset &&
|
||||
hsk->end_offset + 1 >= recv_buf[pos].start_offset) {
|
||||
memcpy(&recv_buf[pos].data.data[hsk->start_offset],
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From cf3f1955e58cbcc10373b841bb101fb058565d87 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Wed, 1 Apr 2026 19:51:45 +0200
|
||||
Subject: [PATCH 5/8] tests/mini-dtls-fragments: extend with a #1816 reproducer
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/mini-dtls-fragments.c | 119 ++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 119 insertions(+)
|
||||
|
||||
diff --git a/tests/mini-dtls-fragments.c b/tests/mini-dtls-fragments.c
|
||||
index 0abe557f7..d997ad64f 100644
|
||||
--- a/tests/mini-dtls-fragments.c
|
||||
+++ b/tests/mini-dtls-fragments.c
|
||||
@@ -106,6 +106,11 @@ static int pull_timeout(gnutls_transport_ptr_t tr, unsigned ms)
|
||||
return 1;
|
||||
}
|
||||
|
||||
+static int c2s_pull_timeout_once(gnutls_transport_ptr_t tr, unsigned ms)
|
||||
+{
|
||||
+ return c2s.head != c2s.tail ? 1 : 0;
|
||||
+}
|
||||
+
|
||||
static ssize_t server_pull(gnutls_transport_ptr_t tr, void *b, size_t l)
|
||||
{
|
||||
return queue_get(&c2s, (gnutls_session_t)tr, b, l);
|
||||
@@ -196,10 +201,124 @@ static void test(gnutls_push_func client_push)
|
||||
gnutls_certificate_free_credentials(scred);
|
||||
}
|
||||
|
||||
+static void test_malicious1816(void)
|
||||
+{
|
||||
+ /* dgram1: msg_len=50, frag_offset=25, frag_len=25 */
|
||||
+ static const uint8_t dgram1_hdr[] = {
|
||||
+ 0x16, /* type: handshake */
|
||||
+ 0xfe, 0xfd, /* version: DTLS 1.2 */
|
||||
+ 0x00, 0x00, /* epoch: 0 */
|
||||
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* seq: 0 */
|
||||
+ 0x00, 0x25, /* record_length: 37 */
|
||||
+ 0x01, /* msg_type: ClientHello */
|
||||
+ 0x00, 0x00, 0x32, /* msg_length: 50 */
|
||||
+ 0x00, 0x00, /* msg_seq: 0 */
|
||||
+ 0x00, 0x00, 0x19, /* frag_offset: 25 */
|
||||
+ 0x00, 0x00, 0x19, /* frag_length: 25 */
|
||||
+ };
|
||||
+ /* dgram2: msg_len=3000, frag_offset=0, frag_len=48 */
|
||||
+ static const uint8_t dgram2_hdr[] = {
|
||||
+ 0x16, /* type: handshake */
|
||||
+ 0xfe, 0xfd, /* version: DTLS 1.2 */
|
||||
+ 0x00, 0x00, /* epoch: 0 */
|
||||
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* seq: 1 */
|
||||
+ 0x00, 0x3c, /* record_length: 60 */
|
||||
+ 0x01, /* msg_type: ClientHello */
|
||||
+ 0x00, 0x0b, 0xb8, /* msg_length: 3000 */
|
||||
+ 0x00, 0x00, /* msg_seq: 0 */
|
||||
+ 0x00, 0x00, 0x00, /* frag_offset: 0 */
|
||||
+ 0x00, 0x00, 0x30, /* frag_length: 48 */
|
||||
+ };
|
||||
+ /* dgram3: msg_len=3000, frag_offset=40, frag_len=1475 */
|
||||
+ static const uint8_t dgram3_hdr[] = {
|
||||
+ 0x16, /* type: handshake */
|
||||
+ 0xfe, 0xfd, /* version: DTLS 1.2 */
|
||||
+ 0x00, 0x00, /* epoch: 0 */
|
||||
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, /* seq: 2 */
|
||||
+ 0x05, 0xcf, /* record_length: 1487 */
|
||||
+ 0x01, /* msg_type: ClientHello */
|
||||
+ 0x00, 0x0b, 0xb8, /* msg_length: 3000 */
|
||||
+ 0x00, 0x00, /* msg_seq: 0 */
|
||||
+ 0x00, 0x00, 0x28, /* frag_offset: 40 */
|
||||
+ 0x00, 0x05, 0xc3, /* frag_length: 1475 */
|
||||
+ };
|
||||
+ /* dgram4: msg_len=3000, frag_offset=1500, frag_len=1475 */
|
||||
+ static const uint8_t dgram4_hdr[] = {
|
||||
+ 0x16, /* type: handshake */
|
||||
+ 0xfe, 0xfd, /* version: DTLS 1.2 */
|
||||
+ 0x00, 0x00, /* epoch: 0 */
|
||||
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, /* seq: 3 */
|
||||
+ 0x05, 0xcf, /* record_length: 1487 */
|
||||
+ 0x01, /* msg_type: ClientHello */
|
||||
+ 0x00, 0x0b, 0xb8, /* msg_length: 3000 */
|
||||
+ 0x00, 0x00, /* msg_seq: 0 */
|
||||
+ 0x00, 0x05, 0xdc, /* frag_offset: 1500 */
|
||||
+ 0x00, 0x05, 0xc3, /* frag_length: 1475 */
|
||||
+ };
|
||||
+ gnutls_session_t server;
|
||||
+ gnutls_certificate_credentials_t scred;
|
||||
+ uint8_t dgram[1500];
|
||||
+ int sr;
|
||||
+
|
||||
+ if (debug)
|
||||
+ gnutls_global_set_log_level(4711);
|
||||
+
|
||||
+ gnutls_certificate_allocate_credentials(&scred);
|
||||
+ gnutls_certificate_set_x509_key_mem(scred, &server_cert, &server_key,
|
||||
+ GNUTLS_X509_FMT_PEM);
|
||||
+
|
||||
+ gnutls_init(&server, GNUTLS_SERVER | GNUTLS_DATAGRAM);
|
||||
+ gnutls_priority_set_direct(server, "NORMAL:+VERS-DTLS1.2", NULL);
|
||||
+ gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, scred);
|
||||
+
|
||||
+ gnutls_dtls_set_timeouts(server, 80 * 1000, 8 * 1000);
|
||||
+
|
||||
+ gnutls_transport_set_ptr(server, server);
|
||||
+ gnutls_transport_set_push_function(server, server_push);
|
||||
+ gnutls_transport_set_pull_function(server, server_pull);
|
||||
+ gnutls_transport_set_pull_timeout_function(server,
|
||||
+ c2s_pull_timeout_once);
|
||||
+
|
||||
+ memset(dgram, 0, sizeof(dgram));
|
||||
+ memcpy(dgram, dgram1_hdr, 25);
|
||||
+ queue_put(&c2s, dgram, 25 + 25);
|
||||
+
|
||||
+ memset(dgram, 0, sizeof(dgram));
|
||||
+ memcpy(dgram, dgram2_hdr, 25);
|
||||
+ queue_put(&c2s, dgram, 25 + 48);
|
||||
+
|
||||
+ memset(dgram, 0, sizeof(dgram));
|
||||
+ memcpy(dgram, dgram3_hdr, 25);
|
||||
+ queue_put(&c2s, dgram, 25 + 1475);
|
||||
+
|
||||
+ memset(dgram, 0, sizeof(dgram));
|
||||
+ memcpy(dgram, dgram4_hdr, 25);
|
||||
+ queue_put(&c2s, dgram, 25 + 1475);
|
||||
+
|
||||
+ gnutls_global_set_log_function(server_log_func);
|
||||
+ do {
|
||||
+ sr = gnutls_handshake(server); /* invalid write if vulnerable */
|
||||
+ } while (c2s.head != c2s.tail && !gnutls_error_is_fatal(sr));
|
||||
+ if (sr != GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
|
||||
+ fail("server: expected GNUTLS_E_UNEXPECTED_PACKET_LENGTH, "
|
||||
+ "got: %s\n",
|
||||
+ gnutls_strerror(sr));
|
||||
+
|
||||
+ success("OK\n");
|
||||
+
|
||||
+ queue_reset(&c2s);
|
||||
+ queue_reset(&s2c);
|
||||
+
|
||||
+ gnutls_deinit(server);
|
||||
+ gnutls_certificate_free_credentials(scred);
|
||||
+}
|
||||
+
|
||||
void doit(void)
|
||||
{
|
||||
global_init();
|
||||
test(client_push_normal);
|
||||
+ success("malicious reassembly bug exploitation (#1816):\n");
|
||||
+ test_malicious1816();
|
||||
gnutls_global_deinit();
|
||||
}
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From bb427ff74dba849d40753ed9c8511e873f762743 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 20 Apr 2026 16:08:11 +0200
|
||||
Subject: [PATCH 6/8] tests/mini-dtls-fragments: extend with fragmenting
|
||||
ClientHello
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/mini-dtls-fragments.c | 107 ++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 107 insertions(+)
|
||||
|
||||
diff --git a/tests/mini-dtls-fragments.c b/tests/mini-dtls-fragments.c
|
||||
index d997ad64f..a1fa7f8dd 100644
|
||||
--- a/tests/mini-dtls-fragments.c
|
||||
+++ b/tests/mini-dtls-fragments.c
|
||||
@@ -132,6 +132,39 @@ static ssize_t client_push_normal(gnutls_transport_ptr_t tr, const void *b,
|
||||
return queue_put(&c2s, b, l);
|
||||
}
|
||||
|
||||
+static void write_u16(uint8_t *p, uint16_t val)
|
||||
+{
|
||||
+ p[0] = val >> 8;
|
||||
+ p[1] = val & 0xff;
|
||||
+}
|
||||
+
|
||||
+static void write_u24(uint8_t *p, uint32_t val)
|
||||
+{
|
||||
+ p[0] = (val >> 16) & 0xff;
|
||||
+ p[1] = (val >> 8) & 0xff;
|
||||
+ p[2] = val & 0xff;
|
||||
+}
|
||||
+
|
||||
+static void write_u48(uint8_t *p, uint64_t seq)
|
||||
+{
|
||||
+ int i;
|
||||
+ for (i = 5; i >= 0; i--) {
|
||||
+ p[i] = seq & 0xff;
|
||||
+ seq >>= 8;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static uint64_t read_u48(const uint8_t *p)
|
||||
+{
|
||||
+ uint64_t seq = 0;
|
||||
+ int i;
|
||||
+ for (i = 5; i >= 0; i--) {
|
||||
+ seq <<= 8;
|
||||
+ seq |= p[i];
|
||||
+ }
|
||||
+ return seq;
|
||||
+}
|
||||
+
|
||||
static void test(gnutls_push_func client_push)
|
||||
{
|
||||
gnutls_session_t client, server;
|
||||
@@ -313,12 +346,86 @@ static void test_malicious1816(void)
|
||||
gnutls_certificate_free_credentials(scred);
|
||||
}
|
||||
|
||||
+static ssize_t queue_put_renumbered(queue_t *q, const uint8_t *data, size_t l,
|
||||
+ int delta_n)
|
||||
+{
|
||||
+ if (delta_n == 0 || l < 13 || data[3] != 0 || data[4] != 0)
|
||||
+ return queue_put(&c2s, data, l);
|
||||
+
|
||||
+ uint8_t *p = malloc(l);
|
||||
+ assert(p);
|
||||
+ memcpy(p, data, l);
|
||||
+ write_u48(p + 5, read_u48(p + 5) + delta_n);
|
||||
+ ssize_t ret = queue_put(q, p, l);
|
||||
+ free(p);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void split_client_hello(const uint8_t *data, size_t len, uint8_t **frag1,
|
||||
+ size_t *frag1_len, uint8_t **frag2,
|
||||
+ size_t *frag2_len)
|
||||
+{
|
||||
+ size_t body_size = len - 25;
|
||||
+ *frag1_len = 13 + 12 + 1;
|
||||
+ *frag2_len = 13 + 12 + (body_size - 1);
|
||||
+
|
||||
+ *frag1 = malloc(13 + 12 + 1);
|
||||
+ assert(*frag1);
|
||||
+ *frag2 = malloc(13 + 12 + body_size - 1);
|
||||
+ assert(*frag2);
|
||||
+
|
||||
+ /* first fragment: record header + handshake header + first body byte */
|
||||
+ memcpy(*frag1, data, 13); /* record header */
|
||||
+ write_u16(*frag1 + 11, 12 + 1); /* record length */
|
||||
+ memcpy(*frag1 + 13, data + 13, 12); /* handshake header */
|
||||
+ write_u24(*frag1 + 19, 0); /* fragment_offset = 0 */
|
||||
+ write_u24(*frag1 + 22, 1); /* fragment_length = 1 */
|
||||
+ (*frag1)[25] = data[25]; /* first body byte */
|
||||
+
|
||||
+ /* second fragment: record header + handshake header + remaining body */
|
||||
+ memcpy(*frag2, data, 13); /* record header */
|
||||
+ write_u16(*frag2 + 11, *frag2_len - 13); /* record length */
|
||||
+ write_u48(*frag2 + 5, read_u48(*frag2 + 5) + 1); /* sequence number */
|
||||
+ memcpy(*frag2 + 13, data + 13, 12); /* handshake header */
|
||||
+ write_u24(*frag2 + 19, 1); /* fragment_offset = 1 */
|
||||
+ write_u24(*frag2 + 22, body_size - 1); /* shortened fragment_length */
|
||||
+ memcpy(*frag2 + 25, data + 26, body_size - 1); /* remaining body */
|
||||
+}
|
||||
+
|
||||
+static ssize_t client_push_split_hello(gnutls_transport_ptr_t tr, const void *b,
|
||||
+ size_t l)
|
||||
+{
|
||||
+ static int seq_offset = 0; /* for renumbering follow-up epoch0 ones */
|
||||
+
|
||||
+ const uint8_t *data = (const uint8_t *)b;
|
||||
+ uint8_t *frag1, *frag2;
|
||||
+ size_t frag1_len, frag2_len;
|
||||
+
|
||||
+ /* Pass through anything that isn't an epoch0 ClientHello with body */
|
||||
+ if (l < 13 + 12 + 1 || /* too short for DTLS record header */
|
||||
+ data[0] != 22 || /* not a handshake record */
|
||||
+ data[3] != 0 || data[4] != 0 || /* not epoch 0 */
|
||||
+ data[13] != 1) /* not ClientHello */
|
||||
+ return queue_put_renumbered(&c2s, b, l, seq_offset);
|
||||
+
|
||||
+ /* epoch0 Client Hello: special treatment of splitting into fragments */
|
||||
+ split_client_hello(data, l, &frag1, &frag1_len, &frag2, &frag2_len);
|
||||
+ queue_put(&c2s, frag1, frag1_len);
|
||||
+ queue_put(&c2s, frag2, frag2_len);
|
||||
+ free(frag1);
|
||||
+ free(frag2);
|
||||
+ seq_offset++;
|
||||
+ return l;
|
||||
+}
|
||||
+
|
||||
void doit(void)
|
||||
{
|
||||
global_init();
|
||||
test(client_push_normal);
|
||||
success("malicious reassembly bug exploitation (#1816):\n");
|
||||
test_malicious1816();
|
||||
+ success("split client hello smoke-test\n");
|
||||
+ test(client_push_split_hello);
|
||||
gnutls_global_deinit();
|
||||
}
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 092c65d004e2f125f2fea3db84d801ac49a09f78 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 20 Apr 2026 16:32:02 +0200
|
||||
Subject: [PATCH 7/8] buffers: match DTLS datagrams by sequence number
|
||||
|
||||
DTLS handshake fragment reassembly previously matched incoming fragments
|
||||
by handshake type only, without checking the sequence number.
|
||||
This allowed fragments from different handshake messages
|
||||
to be merged into the same reassembly buffer.
|
||||
|
||||
Now sequence number is accounted for during reassembly,
|
||||
ensuring fragments are only merged when they belong
|
||||
to the same handshake message.
|
||||
|
||||
Reported-by: Zou Dikai
|
||||
Fixes: #1839
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/buffers.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/buffers.c b/lib/buffers.c
|
||||
index 20ff909bd..48715adcc 100644
|
||||
--- a/lib/buffers.c
|
||||
+++ b/lib/buffers.c
|
||||
@@ -996,7 +996,8 @@ static int merge_handshake_packet(gnutls_session_t session,
|
||||
session->internals.handshake_recv_buffer;
|
||||
|
||||
for (i = 0; i < session->internals.handshake_recv_buffer_size; i++) {
|
||||
- if (recv_buf[i].htype == hsk->htype) {
|
||||
+ if (recv_buf[i].htype == hsk->htype &&
|
||||
+ recv_buf[i].sequence == hsk->sequence) {
|
||||
exists = 1;
|
||||
pos = i;
|
||||
break;
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From a2b41be83a1a3529c551ccf54958da91a656550e Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 20 Apr 2026 16:36:08 +0200
|
||||
Subject: [PATCH 8/8] tests/mini-dtls-fragments: #1839 mismatching message_seq
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/mini-dtls-fragments.c | 54 ++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 47 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/tests/mini-dtls-fragments.c b/tests/mini-dtls-fragments.c
|
||||
index a1fa7f8dd..77daa6225 100644
|
||||
--- a/tests/mini-dtls-fragments.c
|
||||
+++ b/tests/mini-dtls-fragments.c
|
||||
@@ -165,7 +165,7 @@ static uint64_t read_u48(const uint8_t *p)
|
||||
return seq;
|
||||
}
|
||||
|
||||
-static void test(gnutls_push_func client_push)
|
||||
+static void test(gnutls_push_func client_push, bool expect_success)
|
||||
{
|
||||
gnutls_session_t client, server;
|
||||
gnutls_certificate_credentials_t ccred, scred;
|
||||
@@ -216,12 +216,22 @@ static void test(gnutls_push_func client_push)
|
||||
sr = gnutls_handshake(server);
|
||||
if (!sr || gnutls_error_is_fatal(sr))
|
||||
sdone = true;
|
||||
+
|
||||
+ if (c2s.head == c2s.tail && s2c.head == s2c.tail)
|
||||
+ break; /* speed the test up */
|
||||
}
|
||||
|
||||
- if (cr)
|
||||
- fail("client: %s\n", gnutls_strerror(cr));
|
||||
- if (sr)
|
||||
- fail("server: %s\n", gnutls_strerror(sr));
|
||||
+ if (expect_success) {
|
||||
+ if (cr)
|
||||
+ fail("client: %s\n", gnutls_strerror(cr));
|
||||
+ if (sr)
|
||||
+ fail("server: %s\n", gnutls_strerror(sr));
|
||||
+
|
||||
+ } else {
|
||||
+ if (cr == 0 && sr == 0)
|
||||
+ fail("handshake unexpectedly succeeded: %s / %s\n",
|
||||
+ gnutls_strerror(cr), gnutls_strerror(sr));
|
||||
+ }
|
||||
|
||||
success("OK\n");
|
||||
|
||||
@@ -418,14 +428,44 @@ static ssize_t client_push_split_hello(gnutls_transport_ptr_t tr, const void *b,
|
||||
return l;
|
||||
}
|
||||
|
||||
+static ssize_t client_push_split_hello_bad_seq(gnutls_transport_ptr_t tr,
|
||||
+ const void *b, size_t l)
|
||||
+{
|
||||
+ /* gnutls wasn't matching on message_seq on merging, see #1839 */
|
||||
+ static int seq_offset = 0; /* for renumbering follow-up epoch0 ones */
|
||||
+
|
||||
+ const uint8_t *data = (const uint8_t *)b;
|
||||
+ uint8_t *frag1, *frag2;
|
||||
+ size_t frag1_len, frag2_len;
|
||||
+
|
||||
+ /* Pass through anything that isn't an epoch0 ClientHello with body */
|
||||
+ if (l < 13 + 12 + 1 || /* too short for DTLS record header */
|
||||
+ data[0] != 22 || /* not a handshake record */
|
||||
+ data[3] != 0 || data[4] != 0 || /* not epoch 0 */
|
||||
+ data[13] != 1) /* not ClientHello */
|
||||
+ return queue_put_renumbered(&c2s, b, l, seq_offset);
|
||||
+
|
||||
+ /* epoch0 Client Hello: special treatment of splitting into fragments */
|
||||
+ split_client_hello(data, l, &frag1, &frag1_len, &frag2, &frag2_len);
|
||||
+ queue_put(&c2s, frag1, frag1_len);
|
||||
+ frag2[18]++; /* WRONG, message_seq mismatch must be rejected, #1839 */
|
||||
+ queue_put(&c2s, frag2, frag2_len);
|
||||
+ free(frag1);
|
||||
+ free(frag2);
|
||||
+ seq_offset++;
|
||||
+ return l;
|
||||
+}
|
||||
+
|
||||
void doit(void)
|
||||
{
|
||||
global_init();
|
||||
- test(client_push_normal);
|
||||
+ test(client_push_normal, true);
|
||||
success("malicious reassembly bug exploitation (#1816):\n");
|
||||
test_malicious1816();
|
||||
success("split client hello smoke-test\n");
|
||||
- test(client_push_split_hello);
|
||||
+ test(client_push_split_hello, true);
|
||||
+ success("split client hello smoke-test and mangle sequence number\n");
|
||||
+ test(client_push_split_hello_bad_seq, false);
|
||||
gnutls_global_deinit();
|
||||
}
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
166
SOURCES/gnutls-3.6.16-CVE-2026-3833-nc-case.patch
Normal file
166
SOURCES/gnutls-3.6.16-CVE-2026-3833-nc-case.patch
Normal file
@ -0,0 +1,166 @@
|
||||
From 19f6508647bdcd3ce21130201e484d7ca6d962c5 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 16 Mar 2026 15:29:40 +0100
|
||||
Subject: [PATCH 1/2] x509/name-constraints: compare domain names
|
||||
case-insensitive
|
||||
|
||||
RFC 5280 7.2:
|
||||
> When comparing DNS names for equality, conforming implementations
|
||||
> MUST perform a case-insensitive exact match on the entire DNS name.
|
||||
> When evaluating name constraints, conforming implementations MUST
|
||||
> perform a case-insensitive exact match on a label-by-label basis.
|
||||
|
||||
Domain name comparison during name constraints processing
|
||||
was case-sensitive. For excluded name constraints, this could lead to
|
||||
incorrectly accepting domain names that should've been rejected.
|
||||
The code for comparing domain names and domain name parts of emails
|
||||
has been modified to perform case-insensitive comparison instead.
|
||||
|
||||
Reported-by: Oleh Konko <security@1seal.org>
|
||||
Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
|
||||
Fixes: #1223
|
||||
Fixes: #1803
|
||||
Fixes: #1852
|
||||
Fixes: CVE-2026-3833
|
||||
Fixes: GNUTLS-SA-2026-04-29-5
|
||||
CVSS: 7.4 High CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/x509/name_constraints.c | 23 ++++++++++++++++++++---
|
||||
1 file changed, 20 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c
|
||||
index 197fc47ac..a126123b1 100644
|
||||
--- a/lib/x509/name_constraints.c
|
||||
+++ b/lib/x509/name_constraints.c
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <x509_int.h>
|
||||
#include <x509_ext_int.h>
|
||||
#include <libtasn1.h>
|
||||
+#include "c-strcase.h"
|
||||
|
||||
#include "ip.h"
|
||||
#include "ip-in-cidr.h"
|
||||
@@ -80,7 +81,7 @@ enum name_constraint_relation {
|
||||
NC_SORTS_AFTER = 2 /* unrelated constraints */
|
||||
};
|
||||
|
||||
-/* A helper to compare just a pair of strings with this rich comparison */
|
||||
+/* Helpers to compare just a pair of strings with this rich comparison */
|
||||
static enum name_constraint_relation
|
||||
compare_strings(const void *n1, size_t n1_len, const void *n2, size_t n2_len)
|
||||
{
|
||||
@@ -96,6 +97,22 @@ compare_strings(const void *n1, size_t n1_len, const void *n2, size_t n2_len)
|
||||
return NC_EQUAL;
|
||||
}
|
||||
|
||||
+static enum name_constraint_relation
|
||||
+compare_strings_case_insensitive(const void *n1, size_t n1_len, const void *n2,
|
||||
+ size_t n2_len)
|
||||
+{
|
||||
+ int r = c_strncasecmp(n1, n2, MIN(n1_len, n2_len));
|
||||
+ if (r < 0)
|
||||
+ return NC_SORTS_BEFORE;
|
||||
+ if (r > 0)
|
||||
+ return NC_SORTS_AFTER;
|
||||
+ if (n1_len < n2_len)
|
||||
+ return NC_SORTS_BEFORE;
|
||||
+ if (n1_len > n2_len)
|
||||
+ return NC_SORTS_AFTER;
|
||||
+ return NC_EQUAL;
|
||||
+}
|
||||
+
|
||||
/* Rich-compare DNS names. Example order/relationships:
|
||||
* z.x.a INCLUDED_BY x.a BEFORE y.a INCLUDED_BY a BEFORE x.b BEFORE y.b */
|
||||
static enum name_constraint_relation compare_dns_names(const gnutls_datum_t *n1,
|
||||
@@ -121,8 +138,8 @@ static enum name_constraint_relation compare_dns_names(const gnutls_datum_t *n1,
|
||||
while (j && n2->data[j - 1] != '.')
|
||||
j--;
|
||||
|
||||
- rel = compare_strings(&n1->data[i], i_end - i, &n2->data[j],
|
||||
- j_end - j);
|
||||
+ rel = compare_strings_case_insensitive(&n1->data[i], i_end - i,
|
||||
+ &n2->data[j], j_end - j);
|
||||
if (rel == NC_SORTS_BEFORE) /* x.a BEFORE y.a */
|
||||
return NC_SORTS_BEFORE;
|
||||
if (rel == NC_SORTS_AFTER) /* y.a AFTER x.a */
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 0fd5bfe0c777a4be30fb481c78c99d1052297f01 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 16 Mar 2026 15:48:57 +0100
|
||||
Subject: [PATCH 2/2] tests/name-constraints: add case-sensitivity check
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/name-constraints.c | 52 ++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 52 insertions(+)
|
||||
|
||||
diff --git a/tests/name-constraints.c b/tests/name-constraints.c
|
||||
index 64e82ad35..7683da433 100644
|
||||
--- a/tests/name-constraints.c
|
||||
+++ b/tests/name-constraints.c
|
||||
@@ -324,6 +324,58 @@ void doit(void)
|
||||
|
||||
gnutls_x509_name_constraints_deinit(nc);
|
||||
|
||||
+ /* 4b: case insensitivity */
|
||||
+
|
||||
+ ret = gnutls_x509_name_constraints_init(&nc);
|
||||
+ check_for_error(ret);
|
||||
+
|
||||
+ set_name("example.net", &name);
|
||||
+ ret = gnutls_x509_name_constraints_add_excluded(nc, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_for_error(ret);
|
||||
+ set_name("email@example.net", &name);
|
||||
+ ret = gnutls_x509_name_constraints_add_excluded(
|
||||
+ nc, GNUTLS_SAN_RFC822NAME, &name);
|
||||
+ check_for_error(ret);
|
||||
+
|
||||
+ set_name("example.org", &name); /* unrelated: accepted */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_DNSNAME, &name);
|
||||
+ check_test_result(ret, NAME_ACCEPTED, &name);
|
||||
+
|
||||
+ set_name("example.net", &name); /* exact match: rejected */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_DNSNAME, &name);
|
||||
+ check_test_result(ret, NAME_REJECTED, &name);
|
||||
+
|
||||
+ set_name("eXample.net", &name); /* case *insensitive*: rejected */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_DNSNAME, &name);
|
||||
+ check_test_result(ret, NAME_REJECTED, &name);
|
||||
+
|
||||
+ set_name("mail@example.net", &name); /* unrelated: accepted */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_RFC822NAME,
|
||||
+ &name);
|
||||
+ check_test_result(ret, NAME_ACCEPTED, &name);
|
||||
+
|
||||
+ set_name("email@example.net", &name); /* exact match: rejected */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_RFC822NAME,
|
||||
+ &name);
|
||||
+ check_test_result(ret, NAME_REJECTED, &name);
|
||||
+
|
||||
+ set_name("eMail@example.net", &name); /* case *sensitive*: accepted */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_RFC822NAME,
|
||||
+ &name);
|
||||
+ check_test_result(ret, NAME_ACCEPTED, &name);
|
||||
+
|
||||
+ set_name("email@EXAMPLE.NET", &name); /* case *insensitive*: rejected */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_RFC822NAME,
|
||||
+ &name);
|
||||
+ check_test_result(ret, NAME_REJECTED, &name);
|
||||
+
|
||||
+ set_name("www.ExAmPlE.NeT", &name); /* case *insensitive*: inexact */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc, GNUTLS_SAN_DNSNAME, &name);
|
||||
+ check_test_result(ret, NAME_REJECTED, &name);
|
||||
+
|
||||
+ gnutls_x509_name_constraints_deinit(nc);
|
||||
+
|
||||
// Test suite end.
|
||||
|
||||
if (debug)
|
||||
--
|
||||
2.53.0
|
||||
|
||||
95
SOURCES/gnutls-3.6.16-CVE-2026-42009-dtls-qsort.patch
Normal file
95
SOURCES/gnutls-3.6.16-CVE-2026-42009-dtls-qsort.patch
Normal file
@ -0,0 +1,95 @@
|
||||
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: [PATCH 1/2] 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(-)
|
||||
|
||||
diff --git a/lib/buffers.c b/lib/buffers.c
|
||||
index 48715adcc..9f33821dd 100644
|
||||
--- a/lib/buffers.c
|
||||
+++ b/lib/buffers.c
|
||||
@@ -996,8 +996,20 @@ static int merge_handshake_packet(gnutls_session_t session,
|
||||
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;
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
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 2/2] 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(-)
|
||||
|
||||
diff --git a/lib/buffers.c b/lib/buffers.c
|
||||
index 9f33821dd..be51f3aac 100644
|
||||
--- a/lib/buffers.c
|
||||
+++ b/lib/buffers.c
|
||||
@@ -866,11 +866,7 @@ static int handshake_compare(const void *_e1, const void *_e2)
|
||||
{
|
||||
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
|
||||
--
|
||||
2.53.0
|
||||
|
||||
498
SOURCES/gnutls-3.6.16-CVE-2026-42010-psk-nul.patch
Normal file
498
SOURCES/gnutls-3.6.16-CVE-2026-42010-psk-nul.patch
Normal file
@ -0,0 +1,498 @@
|
||||
From 382afcb74f8cdabd2234374c730c33332f06c7b2 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 4 May 2026 10:08:34 +0000
|
||||
Subject: [PATCH 1/6] tests/pskself2: reformat
|
||||
|
||||
---
|
||||
tests/pskself2.c | 19 +++++++++++++------
|
||||
1 file changed, 13 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/tests/pskself2.c b/tests/pskself2.c
|
||||
index 81286a035..c587df060 100644
|
||||
--- a/tests/pskself2.c
|
||||
+++ b/tests/pskself2.c
|
||||
@@ -287,8 +287,7 @@ static void server(int sd, const char *prio)
|
||||
success("server: finished\n");
|
||||
}
|
||||
|
||||
-static
|
||||
-void run_test(const char *prio, unsigned exp_hint)
|
||||
+static void run_test(const char *prio, unsigned exp_hint)
|
||||
{
|
||||
pid_t child;
|
||||
int err;
|
||||
@@ -331,11 +330,19 @@ void doit(void)
|
||||
run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-PSK", 1);
|
||||
|
||||
run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:+PSK", 0);
|
||||
- run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-GROUP-ALL:+GROUP-FFDHE2048:+DHE-PSK", 0);
|
||||
- run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-GROUP-ALL:+GROUP-SECP256R1:+ECDHE-PSK", 0);
|
||||
+ run_test(
|
||||
+ "NORMAL:-VERS-ALL:+VERS-TLS1.2:-GROUP-ALL:+GROUP-FFDHE2048:+DHE-PSK",
|
||||
+ 0);
|
||||
+ run_test(
|
||||
+ "NORMAL:-VERS-ALL:+VERS-TLS1.2:-GROUP-ALL:+GROUP-SECP256R1:+ECDHE-PSK",
|
||||
+ 0);
|
||||
run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK", 0);
|
||||
- run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-FFDHE2048:+DHE-PSK", 0);
|
||||
- run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP256R1:+ECDHE-PSK", 0);
|
||||
+ run_test(
|
||||
+ "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-FFDHE2048:+DHE-PSK",
|
||||
+ 0);
|
||||
+ run_test(
|
||||
+ "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP256R1:+ECDHE-PSK",
|
||||
+ 0);
|
||||
/* the following should work once we support PSK without DH */
|
||||
run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+PSK", 0);
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From e3ffd31846d1e6624338a26ca7fce7d1685b17cd Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Tue, 21 Apr 2026 19:02:43 +0200
|
||||
Subject: [PATCH 2/6] tests/pskself2: extend with RSA-PSK support
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/pskself2.c | 81 ++++++++++++++++++++++++++++++++----------------
|
||||
1 file changed, 54 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/tests/pskself2.c b/tests/pskself2.c
|
||||
index c587df060..974d48334 100644
|
||||
--- a/tests/pskself2.c
|
||||
+++ b/tests/pskself2.c
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
+#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -52,6 +53,7 @@ int main(int argc, char **argv)
|
||||
|
||||
#include "utils.h"
|
||||
#include "extras/hex.h"
|
||||
+#include "cert-common.h"
|
||||
|
||||
/* A very basic TLS client, with PSK authentication.
|
||||
*/
|
||||
@@ -66,12 +68,13 @@ static void tls_log_func(int level, const char *str)
|
||||
#define MAX_BUF 1024
|
||||
#define MSG "Hello TLS"
|
||||
|
||||
-static void client(int sd, const char *prio, unsigned exp_hint)
|
||||
+static void client(int sd, const char *prio, bool exp_hint, bool rsa)
|
||||
{
|
||||
int ret, ii;
|
||||
gnutls_session_t session;
|
||||
char buffer[MAX_BUF + 1];
|
||||
gnutls_psk_client_credentials_t pskcred;
|
||||
+ gnutls_certificate_credentials_t xcred = NULL;
|
||||
/* Need to enable anonymous KX specifically. */
|
||||
const gnutls_datum_t key = { (void *) "DEADBEEF", 8 };
|
||||
gnutls_datum_t user;
|
||||
@@ -111,6 +114,11 @@ static void client(int sd, const char *prio, unsigned exp_hint)
|
||||
*/
|
||||
gnutls_credentials_set(session, GNUTLS_CRD_PSK, pskcred);
|
||||
|
||||
+ if (rsa) {
|
||||
+ gnutls_certificate_allocate_credentials(&xcred);
|
||||
+ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
|
||||
+ }
|
||||
+
|
||||
gnutls_transport_set_int(session, sd);
|
||||
|
||||
/* Perform the TLS handshake
|
||||
@@ -166,6 +174,8 @@ static void client(int sd, const char *prio, unsigned exp_hint)
|
||||
|
||||
gnutls_free(user.data);
|
||||
gnutls_psk_free_client_credentials(pskcred);
|
||||
+ if (xcred)
|
||||
+ gnutls_certificate_free_credentials(xcred);
|
||||
|
||||
gnutls_global_deinit();
|
||||
}
|
||||
@@ -195,9 +205,10 @@ pskfunc(gnutls_session_t session, const gnutls_datum_t *username,
|
||||
}
|
||||
|
||||
|
||||
-static void server(int sd, const char *prio)
|
||||
+static void server(int sd, const char *prio, bool rsa)
|
||||
{
|
||||
gnutls_psk_server_credentials_t server_pskcred;
|
||||
+ gnutls_certificate_credentials_t serverx509cred = NULL;
|
||||
int ret;
|
||||
gnutls_session_t session;
|
||||
gnutls_datum_t psk_username;
|
||||
@@ -217,6 +228,13 @@ static void server(int sd, const char *prio)
|
||||
gnutls_psk_set_server_credentials_hint(server_pskcred, "hint");
|
||||
gnutls_psk_set_server_credentials_function2(server_pskcred, pskfunc);
|
||||
|
||||
+ if (rsa) {
|
||||
+ gnutls_certificate_allocate_credentials(&serverx509cred);
|
||||
+ gnutls_certificate_set_x509_key_mem(serverx509cred,
|
||||
+ &server_cert, &server_key,
|
||||
+ GNUTLS_X509_FMT_PEM);
|
||||
+ }
|
||||
+
|
||||
gnutls_init(&session, GNUTLS_SERVER);
|
||||
|
||||
/* avoid calling all the priority functions, since the defaults
|
||||
@@ -225,6 +243,9 @@ static void server(int sd, const char *prio)
|
||||
gnutls_priority_set_direct(session, prio, NULL);
|
||||
|
||||
gnutls_credentials_set(session, GNUTLS_CRD_PSK, server_pskcred);
|
||||
+ if (serverx509cred)
|
||||
+ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
|
||||
+ serverx509cred);
|
||||
|
||||
gnutls_transport_set_int(session, sd);
|
||||
ret = gnutls_handshake(session);
|
||||
@@ -280,6 +301,8 @@ static void server(int sd, const char *prio)
|
||||
gnutls_deinit(session);
|
||||
|
||||
gnutls_psk_free_server_credentials(server_pskcred);
|
||||
+ if (serverx509cred)
|
||||
+ gnutls_certificate_free_credentials(serverx509cred);
|
||||
|
||||
gnutls_global_deinit();
|
||||
|
||||
@@ -287,7 +310,7 @@ static void server(int sd, const char *prio)
|
||||
success("server: finished\n");
|
||||
}
|
||||
|
||||
-static void run_test(const char *prio, unsigned exp_hint)
|
||||
+static void run_test(const char *prio, bool exp_hint, bool rsa)
|
||||
{
|
||||
pid_t child;
|
||||
int err;
|
||||
@@ -313,42 +336,46 @@ static void run_test(const char *prio, unsigned exp_hint)
|
||||
int status;
|
||||
/* parent */
|
||||
close(sockets[1]);
|
||||
- server(sockets[0], prio);
|
||||
+ server(sockets[0], prio, rsa);
|
||||
wait(&status);
|
||||
check_wait_status(status);
|
||||
} else {
|
||||
close(sockets[0]);
|
||||
- client(sockets[1], prio, exp_hint);
|
||||
+ client(sockets[1], prio, exp_hint, rsa);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
void doit(void)
|
||||
{
|
||||
- run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", 1);
|
||||
- run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-PSK", 1);
|
||||
- run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-PSK", 1);
|
||||
-
|
||||
- run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:+PSK", 0);
|
||||
- run_test(
|
||||
- "NORMAL:-VERS-ALL:+VERS-TLS1.2:-GROUP-ALL:+GROUP-FFDHE2048:+DHE-PSK",
|
||||
- 0);
|
||||
- run_test(
|
||||
- "NORMAL:-VERS-ALL:+VERS-TLS1.2:-GROUP-ALL:+GROUP-SECP256R1:+ECDHE-PSK",
|
||||
- 0);
|
||||
- run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK", 0);
|
||||
- run_test(
|
||||
- "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-FFDHE2048:+DHE-PSK",
|
||||
- 0);
|
||||
- run_test(
|
||||
- "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP256R1:+ECDHE-PSK",
|
||||
- 0);
|
||||
+ run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", true, false);
|
||||
+ run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-PSK", true,
|
||||
+ false);
|
||||
+ run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-PSK", true, false);
|
||||
+
|
||||
+ run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:+PSK", false, false);
|
||||
+ run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:"
|
||||
+ "-GROUP-ALL:+GROUP-FFDHE2048:+DHE-PSK",
|
||||
+ false, false);
|
||||
+ run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:"
|
||||
+ "-GROUP-ALL:+GROUP-SECP256R1:+ECDHE-PSK",
|
||||
+ false, false);
|
||||
+ run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK", false, false);
|
||||
+ run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:"
|
||||
+ "-GROUP-ALL:+GROUP-FFDHE2048:+DHE-PSK",
|
||||
+ false, false);
|
||||
+ run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:"
|
||||
+ "-GROUP-ALL:+GROUP-SECP256R1:+ECDHE-PSK",
|
||||
+ false, false);
|
||||
/* the following should work once we support PSK without DH */
|
||||
- run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+PSK", 0);
|
||||
+ run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+PSK", false, false);
|
||||
+
|
||||
+ run_test("NORMAL:-KX-ALL:+PSK", false, false);
|
||||
+ run_test("NORMAL:-KX-ALL:+ECDHE-PSK", false, false);
|
||||
+ run_test("NORMAL:-KX-ALL:+DHE-PSK", false, false);
|
||||
|
||||
- run_test("NORMAL:-KX-ALL:+PSK", 0);
|
||||
- run_test("NORMAL:-KX-ALL:+ECDHE-PSK", 0);
|
||||
- run_test("NORMAL:-KX-ALL:+DHE-PSK", 0);
|
||||
+ /* RSA-PSK */
|
||||
+ run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+RSA-PSK", false, true);
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From cb1833afd9b6309563211b1c0a7c291f52ca98d5 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Tue, 21 Apr 2026 19:26:10 +0200
|
||||
Subject: [PATCH 3/6] lib/auth/rsa_psk: fix binary PSK identity lookup
|
||||
|
||||
A server looking up PSK username with a NUL-character in it
|
||||
was wrongfully matching username truncated at a NUL-character.
|
||||
Fix the check to compare up to the full username length.
|
||||
|
||||
Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
|
||||
Fixes: #1850
|
||||
Fixes: CVE-2026-42010
|
||||
Fixes: GNUTLS-SA-2026-04-29-4
|
||||
CVSS: 7.1 High CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/auth/rsa_psk.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/auth/rsa_psk.c b/lib/auth/rsa_psk.c
|
||||
index 8f3fe5a4b..8813eeeec 100644
|
||||
--- a/lib/auth/rsa_psk.c
|
||||
+++ b/lib/auth/rsa_psk.c
|
||||
@@ -332,7 +332,7 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
|
||||
* filled in if the key is not found.
|
||||
*/
|
||||
ret =
|
||||
- _gnutls_psk_pwd_find_entry(session, info->username, strlen(info->username), &pwd_psk);
|
||||
+ _gnutls_psk_pwd_find_entry(session, info->username, info->username_len, &pwd_psk);
|
||||
if (ret < 0)
|
||||
return gnutls_assert_val(ret);
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From cf20434d5cb8f3508e6ed2abdcb3e07bf28b9b6f Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Tue, 21 Apr 2026 19:19:42 +0200
|
||||
Subject: [PATCH 4/6] tests/pskself2: test username with NUL in the middle
|
||||
(#1850)
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/pskself2.c | 31 +++++++++++++++++++++----------
|
||||
1 file changed, 22 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/tests/pskself2.c b/tests/pskself2.c
|
||||
index 974d48334..508711aa9 100644
|
||||
--- a/tests/pskself2.c
|
||||
+++ b/tests/pskself2.c
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
+#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -87,12 +87,15 @@ static void client(int sd, const char *prio, bool exp_hint, bool rsa)
|
||||
|
||||
side = "client";
|
||||
|
||||
- user.data = gnutls_malloc(4);
|
||||
+ user.data = gnutls_malloc(5);
|
||||
+ assert(user.data != NULL);
|
||||
+
|
||||
user.data[0] = 0xCA;
|
||||
user.data[1] = 0xFE;
|
||||
- user.data[2] = 0xCA;
|
||||
- user.data[3] = 0xFE;
|
||||
- user.size = 4;
|
||||
+ user.data[2] = 0x00;
|
||||
+ user.data[3] = 0xCA;
|
||||
+ user.data[4] = 0xFE;
|
||||
+ user.size = 5;
|
||||
|
||||
gnutls_psk_allocate_client_credentials(&pskcred);
|
||||
ret = gnutls_psk_set_client_credentials2(pskcred, &user, &key,
|
||||
@@ -191,14 +194,20 @@ static int
|
||||
pskfunc(gnutls_session_t session, const gnutls_datum_t *username,
|
||||
gnutls_datum_t * key)
|
||||
{
|
||||
+ const unsigned char expected_user[] = { 0xCA, 0xFE, 0x00, 0xCA, 0xFE };
|
||||
+ const unsigned char expected_key[] = { 0xDE, 0xAD, 0xBE, 0xEF };
|
||||
+
|
||||
if (debug)
|
||||
printf("psk: Got username with length %d\n", username->size);
|
||||
|
||||
+ /* verify callback received full 5-byte username (#1850) */
|
||||
+ if (username->size != 5 ||
|
||||
+ memcmp(username->data, expected_user, 5) != 0)
|
||||
+ fail("pskfunc: username mismatch: got %u bytes, expected 5\n",
|
||||
+ username->size);
|
||||
+
|
||||
key->data = gnutls_malloc(4);
|
||||
- key->data[0] = 0xDE;
|
||||
- key->data[1] = 0xAD;
|
||||
- key->data[2] = 0xBE;
|
||||
- key->data[3] = 0xEF;
|
||||
+ memcpy(key->data, expected_key, 4);
|
||||
key->size = 4;
|
||||
|
||||
return 0;
|
||||
@@ -212,7 +221,8 @@ static void server(int sd, const char *prio, bool rsa)
|
||||
int ret;
|
||||
gnutls_session_t session;
|
||||
gnutls_datum_t psk_username;
|
||||
- char buffer[MAX_BUF + 1], expected_psk_username[] = { 0xDE, 0xAD, 0xBE, 0xEF };
|
||||
+ char buffer[MAX_BUF + 1];
|
||||
+ const char expected_psk_username[] = { 0xCA, 0xFE, 0x00, 0xCA, 0xFE };
|
||||
|
||||
/* this must be called once in the program
|
||||
*/
|
||||
@@ -265,7 +275,8 @@ static void server(int sd, const char *prio, bool rsa)
|
||||
if (gnutls_psk_server_get_username2(session, &psk_username) < 0)
|
||||
fail("server: Could not get PSK username\n");
|
||||
|
||||
- if (psk_username.size != 4 || memcmp(psk_username.data, expected_psk_username, 4))
|
||||
+ if (psk_username.size != 5 ||
|
||||
+ memcmp(psk_username.data, expected_psk_username, 5))
|
||||
fail("server: Unexpected PSK username\n");
|
||||
|
||||
success("server: PSK username length: %d\n", psk_username.size);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 0f8539fac736a2cdcc79ee4ea5a2f2590a6bea6b Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Tue, 21 Apr 2026 19:49:47 +0200
|
||||
Subject: [PATCH 5/6] tests/pskself2: sprinkle NUL into key for good measure
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/pskself2.c | 10 +++++-----
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/tests/pskself2.c b/tests/pskself2.c
|
||||
index 508711aa9..71c94cc1d 100644
|
||||
--- a/tests/pskself2.c
|
||||
+++ b/tests/pskself2.c
|
||||
@@ -76,7 +76,7 @@ static void client(int sd, const char *prio, bool exp_hint, bool rsa)
|
||||
gnutls_psk_client_credentials_t pskcred;
|
||||
gnutls_certificate_credentials_t xcred = NULL;
|
||||
/* Need to enable anonymous KX specifically. */
|
||||
- const gnutls_datum_t key = { (void *) "DEADBEEF", 8 };
|
||||
+ const gnutls_datum_t key = { (void *) "DEAD00BEEF", 10 };
|
||||
gnutls_datum_t user;
|
||||
const char *hint;
|
||||
|
||||
@@ -195,7 +195,7 @@ pskfunc(gnutls_session_t session, const gnutls_datum_t *username,
|
||||
gnutls_datum_t * key)
|
||||
{
|
||||
const unsigned char expected_user[] = { 0xCA, 0xFE, 0x00, 0xCA, 0xFE };
|
||||
- const unsigned char expected_key[] = { 0xDE, 0xAD, 0xBE, 0xEF };
|
||||
+ const unsigned char expected_key[] = { 0xDE, 0xAD, 0x00, 0xBE, 0xEF };
|
||||
|
||||
if (debug)
|
||||
printf("psk: Got username with length %d\n", username->size);
|
||||
@@ -206,9 +206,9 @@ pskfunc(gnutls_session_t session, const gnutls_datum_t *username,
|
||||
fail("pskfunc: username mismatch: got %u bytes, expected 5\n",
|
||||
username->size);
|
||||
|
||||
- key->data = gnutls_malloc(4);
|
||||
- memcpy(key->data, expected_key, 4);
|
||||
- key->size = 4;
|
||||
+ key->data = gnutls_malloc(5);
|
||||
+ memcpy(key->data, expected_key, 5);
|
||||
+ key->size = 5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From b10ac69270cd5ab4353efa62b92d9e04a5fec464 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 27 Apr 2026 17:16:25 +0200
|
||||
Subject: [PATCH 6/6] lib/auth/psk_passwd: limit the length of the comparison
|
||||
|
||||
Comparing a long username from a password file
|
||||
to a short username from the wire
|
||||
could lead to a heap overread up to the difference in their lengths.
|
||||
|
||||
Fixes: #1864
|
||||
Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/auth/psk_passwd.c | 19 +++++++++++--------
|
||||
1 file changed, 11 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/lib/auth/psk_passwd.c b/lib/auth/psk_passwd.c
|
||||
index 9a9d68c48..c87f2d68e 100644
|
||||
--- a/lib/auth/psk_passwd.c
|
||||
+++ b/lib/auth/psk_passwd.c
|
||||
@@ -78,7 +78,7 @@ static int pwd_put_values(gnutls_datum_t * psk, char *str)
|
||||
static bool username_matches(const gnutls_datum_t *username,
|
||||
const char *line, size_t line_size)
|
||||
{
|
||||
- int retval;
|
||||
+ bool retval;
|
||||
unsigned i;
|
||||
gnutls_datum_t hexline, hex_username = { NULL, 0 };
|
||||
|
||||
@@ -91,7 +91,7 @@ static bool username_matches(const gnutls_datum_t *username,
|
||||
return false;
|
||||
|
||||
if (line_size == 0)
|
||||
- return (username->size == 0);
|
||||
+ return false;
|
||||
|
||||
/* move to first ':' */
|
||||
i = 0;
|
||||
@@ -100,6 +100,9 @@ static bool username_matches(const gnutls_datum_t *username,
|
||||
i++;
|
||||
}
|
||||
|
||||
+ if (line[i] != ':')
|
||||
+ return false;
|
||||
+
|
||||
/* if format is in hex, e.g. #FAFAFA */
|
||||
if (line[0] == '#' && line_size > 1) {
|
||||
hexline.data = (void *) &line[1];
|
||||
@@ -108,17 +111,17 @@ static bool username_matches(const gnutls_datum_t *username,
|
||||
if ((retval = gnutls_hex_decode2(&hexline, &hex_username)) < 0)
|
||||
return gnutls_assert_val(0);
|
||||
|
||||
- if (hex_username.size == username->size)
|
||||
- retval = memcmp(username->data, hex_username.data, username->size);
|
||||
- else
|
||||
- retval = -1;
|
||||
+ retval = hex_username.size == username->size &&
|
||||
+ memcmp(username->data, hex_username.data,
|
||||
+ username->size) == 0;
|
||||
|
||||
_gnutls_free_datum(&hex_username);
|
||||
} else {
|
||||
- retval = strncmp((const char *) username->data, line, MAX(i, username->size));
|
||||
+ retval = i == username->size &&
|
||||
+ strncmp((const char *) username->data, line, i) == 0;
|
||||
}
|
||||
|
||||
- return (retval == 0);
|
||||
+ return retval;
|
||||
}
|
||||
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
176
SOURCES/gnutls-3.6.16-CVE-2026-42011-nc-intersect.patch
Normal file
176
SOURCES/gnutls-3.6.16-CVE-2026-42011-nc-intersect.patch
Normal file
@ -0,0 +1,176 @@
|
||||
From 1dead2faec6320aaba321eb56f20d442df192b83 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Tue, 14 Apr 2026 17:41:30 +0200
|
||||
Subject: [PATCH 1/2] x509/name_constraints: fix intersecting empty constraints
|
||||
|
||||
Permitted name constraints were wrongfully ignored
|
||||
when prior CAs only had excluded name constraints,
|
||||
resulting in a name constraint bypass.
|
||||
|
||||
With this change, they are taken into account and propagate.
|
||||
|
||||
Reported-by: Haruto Kimura (Stella)
|
||||
Fixes: #1824
|
||||
Fixes: CVE-2026-42011
|
||||
Fixes: GNUTLS-SA-2026-04-29-6
|
||||
CVSS: 4.8 Medium CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/x509/name_constraints.c | 3 ---
|
||||
1 file changed, 3 deletions(-)
|
||||
|
||||
diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c
|
||||
index a126123b1..5161f9926 100644
|
||||
--- a/lib/x509/name_constraints.c
|
||||
+++ b/lib/x509/name_constraints.c
|
||||
@@ -717,9 +717,6 @@ static int name_constraints_node_list_intersect(
|
||||
type_bitmask_t types_in_p1 = 0, types_in_p2 = 0;
|
||||
static const unsigned char universal_ip[32] = { 0 };
|
||||
|
||||
- if (permitted->size == 0 || permitted2->size == 0)
|
||||
- return GNUTLS_E_SUCCESS;
|
||||
-
|
||||
/* make sorted views of the arrays */
|
||||
ret = ensure_sorted(permitted);
|
||||
if (ret < 0) {
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 24713b8c63137ce0665b495d22ccce4f5ce05c84 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Tue, 14 Apr 2026 17:49:50 +0200
|
||||
Subject: [PATCH 2/2] tests/name-constraints-merge: extend to cover #1824
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/name-constraints-merge.c | 113 +++++++++++++++++++++++++++++++++
|
||||
1 file changed, 113 insertions(+)
|
||||
|
||||
diff --git a/tests/name-constraints-merge.c b/tests/name-constraints-merge.c
|
||||
index 76430fb80..387395c6c 100644
|
||||
--- a/tests/name-constraints-merge.c
|
||||
+++ b/tests/name-constraints-merge.c
|
||||
@@ -369,6 +369,119 @@ void doit(void)
|
||||
gnutls_x509_name_constraints_deinit(nc1);
|
||||
gnutls_x509_name_constraints_deinit(nc2);
|
||||
|
||||
+ /* 6: test intersecting empty permitted with non-empty permitted
|
||||
+ * NC1: excluded DNS excluded.example.org (empty permitted)
|
||||
+ * NC2: permitted DNS permitted.example.org
|
||||
+ * Expected result:
|
||||
+ * permitted=[permitted.example.org], excluded=[excluded.example.org]
|
||||
+ * unrelated.example.com is rejected
|
||||
+ */
|
||||
+ suite = 6;
|
||||
+
|
||||
+ ret = gnutls_x509_name_constraints_init(&nc1);
|
||||
+ check_for_error(ret);
|
||||
+
|
||||
+ ret = gnutls_x509_name_constraints_init(&nc2);
|
||||
+ check_for_error(ret);
|
||||
+
|
||||
+ set_name("excluded.example.org", &name);
|
||||
+ ret = gnutls_x509_name_constraints_add_excluded(nc1, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_for_error(ret);
|
||||
+
|
||||
+ set_name("permitted.example.org", &name);
|
||||
+ ret = gnutls_x509_name_constraints_add_permitted(
|
||||
+ nc2, GNUTLS_SAN_DNSNAME, &name);
|
||||
+ check_for_error(ret);
|
||||
+
|
||||
+ ret = _gnutls_x509_name_constraints_merge(nc1, nc2);
|
||||
+ check_for_error(ret);
|
||||
+
|
||||
+ set_name("unrelated.example.com", &name); /* entirely unrelated */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_test_result(suite, ret, NAME_REJECTED, &name); /* #1814 */
|
||||
+
|
||||
+ set_name("permitted.example.org", &name); /* permitted, direct */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_test_result(suite, ret, NAME_ACCEPTED, &name); /* sanity */
|
||||
+
|
||||
+ set_name("sub.permitted.example.org", &name); /* permitted, subdomain */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_test_result(suite, ret, NAME_ACCEPTED, &name); /* sanity */
|
||||
+
|
||||
+ set_name("excluded.example.org", &name); /* excluded, direct */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_test_result(suite, ret, NAME_REJECTED, &name); /* sanity */
|
||||
+
|
||||
+ set_name("sub.excluded.example.org", &name); /* excluded, subdomain */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_test_result(suite, ret, NAME_REJECTED, &name); /* sanity */
|
||||
+
|
||||
+ gnutls_x509_name_constraints_deinit(nc1);
|
||||
+ gnutls_x509_name_constraints_deinit(nc2);
|
||||
+
|
||||
+ /* 7: test intersecting non-empty permitted with empty permitted
|
||||
+ * (same as 6, but swapped to ensure order doesn't matter)
|
||||
+ * NC1: permitted DNS permitted.example.org
|
||||
+ * NC2: excluded DNS excluded.example.org (empty permitted)
|
||||
+ * Expected result:
|
||||
+ * permitted=[permitted.example.org], excluded=[excluded.example.org]
|
||||
+ * unrelated.example.com is rejected
|
||||
+ */
|
||||
+ suite = 7;
|
||||
+
|
||||
+ ret = gnutls_x509_name_constraints_init(&nc1);
|
||||
+ check_for_error(ret);
|
||||
+
|
||||
+ ret = gnutls_x509_name_constraints_init(&nc2);
|
||||
+ check_for_error(ret);
|
||||
+
|
||||
+ set_name("permitted.example.org", &name);
|
||||
+ ret = gnutls_x509_name_constraints_add_permitted(
|
||||
+ nc1, GNUTLS_SAN_DNSNAME, &name);
|
||||
+ check_for_error(ret);
|
||||
+
|
||||
+ set_name("excluded.example.org", &name);
|
||||
+ ret = gnutls_x509_name_constraints_add_excluded(nc2, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_for_error(ret);
|
||||
+
|
||||
+ ret = _gnutls_x509_name_constraints_merge(nc1, nc2);
|
||||
+ check_for_error(ret);
|
||||
+
|
||||
+ set_name("unrelated.example.com", &name); /* entirely unrelated */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_test_result(suite, ret, NAME_REJECTED, &name); /* #1814 */
|
||||
+
|
||||
+ set_name("permitted.example.org", &name); /* permitted, direct */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_test_result(suite, ret, NAME_ACCEPTED, &name); /* sanity */
|
||||
+
|
||||
+ set_name("sub.permitted.example.org", &name); /* permitted, subdomain */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_test_result(suite, ret, NAME_ACCEPTED, &name); /* sanity */
|
||||
+
|
||||
+ set_name("excluded.example.org", &name); /* excluded, direct */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_test_result(suite, ret, NAME_REJECTED, &name); /* sanity */
|
||||
+
|
||||
+ set_name("sub.excluded.example.org", &name); /* excluded, subdomain */
|
||||
+ ret = gnutls_x509_name_constraints_check(nc1, GNUTLS_SAN_DNSNAME,
|
||||
+ &name);
|
||||
+ check_test_result(suite, ret, NAME_REJECTED, &name); /* sanity */
|
||||
+
|
||||
+ gnutls_x509_name_constraints_deinit(nc1);
|
||||
+ gnutls_x509_name_constraints_deinit(nc2);
|
||||
+
|
||||
/* Test footer */
|
||||
|
||||
if (debug)
|
||||
--
|
||||
2.53.0
|
||||
|
||||
552
SOURCES/gnutls-3.6.16-CVE-2026-42012-url-san-cn.patch
Normal file
552
SOURCES/gnutls-3.6.16-CVE-2026-42012-url-san-cn.patch
Normal file
@ -0,0 +1,552 @@
|
||||
From fc909c3abddcc2955bebf0de403136ed9ec689c2 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Tue, 28 Apr 2026 15:26:32 +0200
|
||||
Subject: [PATCH 1/6] x509/virt-san: a small OOM-correctness fix
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/x509/virt-san.c | 15 ++++++++-------
|
||||
1 file changed, 8 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/lib/x509/virt-san.c b/lib/x509/virt-san.c
|
||||
index d2adc4e25..4bbfa1e0e 100644
|
||||
--- a/lib/x509/virt-san.c
|
||||
+++ b/lib/x509/virt-san.c
|
||||
@@ -98,26 +98,27 @@ int _gnutls_alt_name_assign_virt_type(struct name_st *name, unsigned type, gnutl
|
||||
if (ret < 0)
|
||||
return gnutls_assert_val(ret);
|
||||
|
||||
- name->type = GNUTLS_SAN_OTHERNAME;
|
||||
name->san.data = encoded.data;
|
||||
name->san.size = encoded.size;
|
||||
- name->othername_oid.data = (void*)gnutls_strdup(oid);
|
||||
- name->othername_oid.size = strlen(oid);
|
||||
break;
|
||||
|
||||
case GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL:
|
||||
ret = _gnutls_krb5_principal_to_der((char*)san->data, &name->san);
|
||||
if (ret < 0)
|
||||
return gnutls_assert_val(ret);
|
||||
-
|
||||
- name->othername_oid.data = (void*)gnutls_strdup(oid);
|
||||
- name->othername_oid.size = strlen(oid);
|
||||
- name->type = GNUTLS_SAN_OTHERNAME;
|
||||
break;
|
||||
|
||||
default:
|
||||
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
||||
}
|
||||
+ ret = _gnutls_set_strdatum(&name->othername_oid, oid,
|
||||
+ strlen(oid));
|
||||
+ if (ret < 0) {
|
||||
+ gnutls_assert();
|
||||
+ _gnutls_free_datum(&name->san);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ name->type = GNUTLS_SAN_OTHERNAME;
|
||||
|
||||
gnutls_free(san->data);
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 5cc003b9688378f6c7934b1df0aa147e80006be4 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Fri, 13 Mar 2026 17:41:33 +0100
|
||||
Subject: [PATCH 2/6] x509: add bare-bones awareness of SRV virtual SAN
|
||||
|
||||
There's no support for constraints, no certtool support, no nothing.
|
||||
Just added what's easy to add because I needed a virtual SAN for them.
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/includes/gnutls/gnutls.h.in | 4 +++-
|
||||
lib/x509/common.h | 1 +
|
||||
lib/x509/name_constraints.c | 3 ++-
|
||||
lib/x509/output.c | 9 ++++++++-
|
||||
lib/x509/virt-san.c | 25 +++++++++++++++++++++++++
|
||||
lib/x509/x509.c | 6 ++++--
|
||||
6 files changed, 43 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
|
||||
index 264da238a..e5906617a 100644
|
||||
--- a/lib/includes/gnutls/gnutls.h.in
|
||||
+++ b/lib/includes/gnutls/gnutls.h.in
|
||||
@@ -2692,6 +2692,7 @@ gnutls_psk_set_server_params_function(gnutls_psk_server_credentials_t
|
||||
* @GNUTLS_SAN_REGISTERED_ID: RegisteredID.
|
||||
* @GNUTLS_SAN_OTHERNAME_XMPP: Virtual SAN, used by certain functions for convenience.
|
||||
* @GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL: Virtual SAN, used by certain functions for convenience.
|
||||
+ * @GNUTLS_SAN_OTHERNAME_SRV: Virtual SAN, used by certain functions for convenience.
|
||||
*
|
||||
* Enumeration of different subject alternative names types.
|
||||
*/
|
||||
@@ -2708,7 +2709,8 @@ typedef enum gnutls_x509_subject_alt_name_t {
|
||||
that they are represented by an otherName value and an OID.
|
||||
Used by gnutls_x509_crt_get_subject_alt_othername_oid. */
|
||||
GNUTLS_SAN_OTHERNAME_XMPP = 1000,
|
||||
- GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL
|
||||
+ GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL,
|
||||
+ GNUTLS_SAN_OTHERNAME_SRV
|
||||
} gnutls_x509_subject_alt_name_t;
|
||||
|
||||
struct gnutls_openpgp_crt_int;
|
||||
diff --git a/lib/x509/common.h b/lib/x509/common.h
|
||||
index 483bd1de6..37ed0b160 100644
|
||||
--- a/lib/x509/common.h
|
||||
+++ b/lib/x509/common.h
|
||||
@@ -102,6 +102,7 @@
|
||||
|
||||
#define XMPP_OID "1.3.6.1.5.5.7.8.5"
|
||||
#define KRB5_PRINCIPAL_OID "1.3.6.1.5.2.2"
|
||||
+#define SRV_OID "1.3.6.1.5.5.7.8.7"
|
||||
#define PKIX1_RSA_PSS_MGF1_OID "1.2.840.113549.1.1.8"
|
||||
|
||||
#define GOST28147_89_OID "1.2.643.2.2.21"
|
||||
diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c
|
||||
index 5161f9926..37e1c098e 100644
|
||||
--- a/lib/x509/name_constraints.c
|
||||
+++ b/lib/x509/name_constraints.c
|
||||
@@ -520,7 +520,8 @@ static int validate_name_constraints_node(gnutls_x509_subject_alt_name_t type,
|
||||
{
|
||||
if (type != GNUTLS_SAN_DNSNAME && type != GNUTLS_SAN_RFC822NAME &&
|
||||
type != GNUTLS_SAN_DN && type != GNUTLS_SAN_URI &&
|
||||
- type != GNUTLS_SAN_IPADDRESS) {
|
||||
+ type != GNUTLS_SAN_IPADDRESS &&
|
||||
+ type != GNUTLS_SAN_OTHERNAME_SRV) {
|
||||
return gnutls_assert_val(GNUTLS_E_X509_UNKNOWN_SAN);
|
||||
}
|
||||
|
||||
diff --git a/lib/x509/output.c b/lib/x509/output.c
|
||||
index 705e8babf..3c996186b 100644
|
||||
--- a/lib/x509/output.c
|
||||
+++ b/lib/x509/output.c
|
||||
@@ -108,8 +108,10 @@ print_name(gnutls_buffer_st *str, const char *prefix, unsigned type, gnutls_datu
|
||||
|
||||
if ((type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_OTHERNAME_XMPP
|
||||
|| type == GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL
|
||||
+ || type == GNUTLS_SAN_OTHERNAME_SRV
|
||||
|| type == GNUTLS_SAN_RFC822NAME
|
||||
- || type == GNUTLS_SAN_URI) && sname != NULL && strlen(sname) != name->size) {
|
||||
+ || type == GNUTLS_SAN_URI) && sname != NULL
|
||||
+ && strlen(sname) != name->size) {
|
||||
adds(str,
|
||||
_("warning: SAN contains an embedded NUL, "
|
||||
"replacing with '!'\n"));
|
||||
@@ -156,6 +158,11 @@ print_name(gnutls_buffer_st *str, const char *prefix, unsigned type, gnutls_datu
|
||||
addf(str, _("%sKRB5Principal: %.*s\n"), prefix, name->size, NON_NULL(name->data));
|
||||
break;
|
||||
|
||||
+ case GNUTLS_SAN_OTHERNAME_SRV:
|
||||
+ addf(str, _("%sSRVName: %.*s\n"), prefix, name->size,
|
||||
+ NON_NULL(name->data));
|
||||
+ break;
|
||||
+
|
||||
default:
|
||||
addf(str, _("%sUnknown name: "), prefix);
|
||||
_gnutls_buffer_hexprint(str, name->data, name->size);
|
||||
diff --git a/lib/x509/virt-san.c b/lib/x509/virt-san.c
|
||||
index 4bbfa1e0e..a59da4299 100644
|
||||
--- a/lib/x509/virt-san.c
|
||||
+++ b/lib/x509/virt-san.c
|
||||
@@ -40,6 +40,9 @@ int san_othername_to_virtual(const char *oid, size_t size)
|
||||
else if ((unsigned) size == (sizeof(KRB5_PRINCIPAL_OID)-1)
|
||||
&& memcmp(oid, KRB5_PRINCIPAL_OID, sizeof(KRB5_PRINCIPAL_OID)-1) == 0)
|
||||
return GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL;
|
||||
+ else if ((unsigned)size == (sizeof(SRV_OID) - 1) &&
|
||||
+ memcmp(oid, SRV_OID, sizeof(SRV_OID) - 1) == 0)
|
||||
+ return GNUTLS_SAN_OTHERNAME_SRV;
|
||||
}
|
||||
|
||||
return GNUTLS_SAN_OTHERNAME;
|
||||
@@ -53,6 +56,8 @@ const char * virtual_to_othername_oid(unsigned type)
|
||||
return XMPP_OID;
|
||||
case GNUTLS_SAN_OTHERNAME_KRB5PRINCIPAL:
|
||||
return KRB5_PRINCIPAL_OID;
|
||||
+ case GNUTLS_SAN_OTHERNAME_SRV:
|
||||
+ return SRV_OID;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@@ -108,6 +113,17 @@ int _gnutls_alt_name_assign_virt_type(struct name_st *name, unsigned type, gnutl
|
||||
return gnutls_assert_val(ret);
|
||||
break;
|
||||
|
||||
+ case GNUTLS_SAN_OTHERNAME_SRV:
|
||||
+ ret = _gnutls_x509_encode_string(
|
||||
+ ASN1_ETYPE_IA5_STRING,
|
||||
+ san->data, san->size,
|
||||
+ &encoded);
|
||||
+ if (ret < 0)
|
||||
+ return gnutls_assert_val(ret);
|
||||
+ name->san.data = encoded.data;
|
||||
+ name->san.size = encoded.size;
|
||||
+ break;
|
||||
+
|
||||
default:
|
||||
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
||||
}
|
||||
@@ -172,6 +188,15 @@ int gnutls_x509_othername_to_virtual(const char *oid,
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
+ case GNUTLS_SAN_OTHERNAME_SRV:
|
||||
+ ret = _gnutls_x509_decode_string
|
||||
+ (ASN1_ETYPE_IA5_STRING, othername->data,
|
||||
+ othername->size, virt, 0);
|
||||
+ if (ret < 0) {
|
||||
+ gnutls_assert();
|
||||
+ return ret;
|
||||
+ }
|
||||
+ return 0;
|
||||
default:
|
||||
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
|
||||
}
|
||||
diff --git a/lib/x509/x509.c b/lib/x509/x509.c
|
||||
index c713f857a..877b88b26 100644
|
||||
--- a/lib/x509/x509.c
|
||||
+++ b/lib/x509/x509.c
|
||||
@@ -1382,7 +1382,8 @@ inline static int is_type_printable(int type)
|
||||
{
|
||||
if (type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_RFC822NAME ||
|
||||
type == GNUTLS_SAN_URI || type == GNUTLS_SAN_OTHERNAME_XMPP ||
|
||||
- type == GNUTLS_SAN_OTHERNAME || type == GNUTLS_SAN_REGISTERED_ID)
|
||||
+ type == GNUTLS_SAN_OTHERNAME_SRV || type == GNUTLS_SAN_OTHERNAME ||
|
||||
+ type == GNUTLS_SAN_REGISTERED_ID)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
@@ -1855,7 +1856,8 @@ get_alt_name(gnutls_subject_alt_names_t san,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
- if (othername_oid && type == GNUTLS_SAN_OTHERNAME && ooid.data) {
|
||||
+ /* API uses othername_oid=0; map to virtual types regardless */
|
||||
+ if (type == GNUTLS_SAN_OTHERNAME && ooid.data) {
|
||||
unsigned vtype;
|
||||
ret = gnutls_x509_othername_to_virtual((char*)ooid.data, &oname, &vtype, &virt);
|
||||
if (ret >= 0) {
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 5a21e1e175f6c853ab3ee39a4d2d9adfb80e3731 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 4 May 2026 10:53:26 +0000
|
||||
Subject: [PATCH 3/6] x509/hostname-verify: use memchr for embedded-null check
|
||||
|
||||
_gnutls_has_embedded_null uses strlen, which reads past the buffer if
|
||||
there is no NUL within the first size bytes. memchr(p, '\0', size) is
|
||||
the bounded equivalent.
|
||||
---
|
||||
lib/x509/hostname-verify.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/x509/hostname-verify.c b/lib/x509/hostname-verify.c
|
||||
index 6ef8ba030..15d548661 100644
|
||||
--- a/lib/x509/hostname-verify.c
|
||||
+++ b/lib/x509/hostname-verify.c
|
||||
@@ -220,7 +220,7 @@ gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
|
||||
if (ret == GNUTLS_SAN_DNSNAME) {
|
||||
found_dnsname = 1;
|
||||
|
||||
- if (_gnutls_has_embedded_null(dnsname, dnsnamesize)) {
|
||||
+ if (memchr(dnsname, '\0', dnsnamesize)) {
|
||||
_gnutls_debug_log("certificate has %s with embedded null in name\n", dnsname);
|
||||
continue;
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 6133fb459b74a9dcfa2d0ff010a4e03c56822d39 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Fri, 13 Mar 2026 17:00:03 +0100
|
||||
Subject: [PATCH 3/6] x509/hostname-verify: refactor and simplify CN fallback
|
||||
logic
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/x509/hostname-verify.c | 17 ++++++++---------
|
||||
1 file changed, 8 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/lib/x509/hostname-verify.c b/lib/x509/hostname-verify.c
|
||||
index 6ef8ba030..698356f32 100644
|
||||
--- a/lib/x509/hostname-verify.c
|
||||
+++ b/lib/x509/hostname-verify.c
|
||||
@@ -112,7 +112,8 @@ gnutls_x509_crt_check_ip(gnutls_x509_crt_t cert,
|
||||
* that we do not fallback to CN-ID if we encounter a supported name
|
||||
* type.
|
||||
*/
|
||||
-#define IS_SAN_SUPPORTED(san) (san==GNUTLS_SAN_DNSNAME||san==GNUTLS_SAN_IPADDRESS)
|
||||
+#define PRECLUDES_CN_FALLBACK(san) \
|
||||
+ (san == GNUTLS_SAN_DNSNAME || san == GNUTLS_SAN_IPADDRESS)
|
||||
|
||||
/**
|
||||
* gnutls_x509_crt_check_hostname2:
|
||||
@@ -154,13 +155,12 @@ gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
|
||||
{
|
||||
char dnsname[MAX_CN];
|
||||
size_t dnsnamesize;
|
||||
- int found_dnsname = 0;
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
struct in_addr ipv4;
|
||||
char *p = NULL;
|
||||
char *a_hostname;
|
||||
- unsigned have_other_addresses = 0;
|
||||
+ bool cn_fallback_allowed = true;
|
||||
gnutls_datum_t out;
|
||||
|
||||
/* check whether @hostname is an ip address */
|
||||
@@ -217,9 +217,10 @@ gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
|
||||
&dnsnamesize,
|
||||
NULL);
|
||||
|
||||
- if (ret == GNUTLS_SAN_DNSNAME) {
|
||||
- found_dnsname = 1;
|
||||
+ if (PRECLUDES_CN_FALLBACK(ret))
|
||||
+ cn_fallback_allowed = false;
|
||||
|
||||
+ if (ret == GNUTLS_SAN_DNSNAME) {
|
||||
if (memchr(dnsname, '\0', dnsnamesize)) {
|
||||
_gnutls_debug_log("certificate has %s with embedded null in name\n", dnsname);
|
||||
continue;
|
||||
@@ -235,13 +236,11 @@ gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
- } else {
|
||||
- if (IS_SAN_SUPPORTED(ret))
|
||||
- have_other_addresses = 1;
|
||||
}
|
||||
}
|
||||
|
||||
- if (!have_other_addresses && !found_dnsname && _gnutls_check_key_purpose(cert, GNUTLS_KP_TLS_WWW_SERVER, 0) != 0) {
|
||||
+ if (cn_fallback_allowed &&
|
||||
+ _gnutls_check_key_purpose(cert, GNUTLS_KP_TLS_WWW_SERVER, 0) != 0) {
|
||||
/* did not get the necessary extension, use CN instead, if the
|
||||
* certificate would have been acceptable for a TLS WWW server purpose.
|
||||
* That is because only for that purpose the CN is a valid field to
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 8dcc6a1f48945997666ac9f10896819edd01a03b Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Fri, 13 Mar 2026 17:02:07 +0100
|
||||
Subject: [PATCH 5/6] x509/hostname-verify: make URI/SRV SAN preclude CN
|
||||
fallback
|
||||
|
||||
URI/SRV SAN did not suppress CN fallback as required by RFC 6125 6.4.4:
|
||||
> a client MUST NOT seek a match for a reference identifier of CN-ID
|
||||
> if the presented identifiers include a DNS-ID, *SRV-ID*, *URI-ID*,
|
||||
> or any application-specific identifier types supported by the client.
|
||||
|
||||
With this change, certificates containing URI or SRV SAN
|
||||
no longer pass DNS hostname checks via CN fallback
|
||||
to avoid potential misuse of such certificates
|
||||
beyond their original purpose.
|
||||
|
||||
Reported-by: Oleh Konko <security@1seal.org>
|
||||
Fixes: #1802
|
||||
Fixes: CVE-2026-42012
|
||||
Fixes: GNUTLS-SA-2026-04-29-7
|
||||
CVSS: 6.5 Medium CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/x509/hostname-verify.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/x509/hostname-verify.c b/lib/x509/hostname-verify.c
|
||||
index eb0fddaa8..d46fd965f 100644
|
||||
--- a/lib/x509/hostname-verify.c
|
||||
+++ b/lib/x509/hostname-verify.c
|
||||
@@ -112,8 +112,9 @@ gnutls_x509_crt_check_ip(gnutls_x509_crt_t cert,
|
||||
* that we do not fallback to CN-ID if we encounter a supported name
|
||||
* type.
|
||||
*/
|
||||
-#define PRECLUDES_CN_FALLBACK(san) \
|
||||
- (san == GNUTLS_SAN_DNSNAME || san == GNUTLS_SAN_IPADDRESS)
|
||||
+#define PRECLUDES_CN_FALLBACK(san) \
|
||||
+ (san == GNUTLS_SAN_DNSNAME || san == GNUTLS_SAN_IPADDRESS || \
|
||||
+ san == GNUTLS_SAN_URI || san == GNUTLS_SAN_OTHERNAME_SRV)
|
||||
|
||||
/**
|
||||
* gnutls_x509_crt_check_hostname2:
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From b39429d77d4ba022f8597c99b84bbd0a073c815b Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Fri, 13 Mar 2026 17:54:56 +0100
|
||||
Subject: [PATCH 6/6] tests/hostname-check: extend to exercise no-CN-fallback
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
tests/hostname-check.c | 141 +++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 141 insertions(+)
|
||||
|
||||
diff --git a/tests/hostname-check.c b/tests/hostname-check.c
|
||||
index 47f8d355d..71481cafb 100644
|
||||
--- a/tests/hostname-check.c
|
||||
+++ b/tests/hostname-check.c
|
||||
@@ -831,6 +831,99 @@ char txt_ip_in_cn[] =
|
||||
"f0+Un2eHAxFcRZPWdPy1/mn83NUMnjquuA/HHcju+pcoZrEwAI3PPQHgsGQ=\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
+char dns_uri_and_cn[] =
|
||||
+ "organization = GnuTLS test\n"
|
||||
+ "cn = example.org\n"
|
||||
+ "expiration_days = 365\n"
|
||||
+ "tls_www_server\n"
|
||||
+ "dns_name = alt.example.org\n"
|
||||
+ "uri = http://example.org/\n"
|
||||
+ "-----BEGIN CERTIFICATE-----\n"
|
||||
+ "MIIEWzCCAsOgAwIBAgIUZ2rP89A5RbTdVMCQ86E9qWLSZz4wDQYJKoZIhvcNAQEL\n"
|
||||
+ "BQAwLDEUMBIGA1UEChMLR251VExTIHRlc3QxFDASBgNVBAMTC2V4YW1wbGUub3Jn\n"
|
||||
+ "MB4XDTI2MDMxMzE1NDIwNVoXDTI3MDMxMzE1NDIwNVowLDEUMBIGA1UEChMLR251\n"
|
||||
+ "VExTIHRlc3QxFDASBgNVBAMTC2V4YW1wbGUub3JnMIIBojANBgkqhkiG9w0BAQEF\n"
|
||||
+ "AAOCAY8AMIIBigKCAYEArEgcC7WDqNJCpO0J3UfCraRWzmwk7soTg7pMmCv1FHWP\n"
|
||||
+ "ywxfXxbl0jvRK/Owyv7q5QRdfcxSYhxydrloCOdWXhGQejgzcpgLu/Y3Ij0CjIzr\n"
|
||||
+ "C38vMSS7yUjAuzB4IYtZsgyuB+bCfGH2Y227ntuniIjEnuekA18gfFemRUQ8PDao\n"
|
||||
+ "EzNAPn8Q3cFlHh5Kr3gkDUduQlRhZdK0ryU/XaAUxz9G9TminIKCl4h1bKNT2pXN\n"
|
||||
+ "08Cg3eOEi3Bl8lCCA7ufODl5frfrDcjNkxqRKN99zMa9A9hcRzYNF9/asX+BXFyh\n"
|
||||
+ "7qbypKXAHBi6xi055+CRIBTxFC960qAluv2cOlo1tzZ0Nta75GhWCqLaVZgI0D0n\n"
|
||||
+ "6SPZPEknVjGPQx1vSnq3ZNdNDdG83yw4QjFtujXdKrflcJafCg3D6LCvEyDPBdYC\n"
|
||||
+ "reTJ9xWNCdsxdzlTdDk11CbxdIz4jA7qA/forbY9Dv7l0iC9d2zWmn4DOv23QIki\n"
|
||||
+ "Uw46/ymnpeFaUTyNyyNHAgMBAAGjdTBzMAwGA1UdEwEB/wQCMAAwLwYDVR0RBCgw\n"
|
||||
+ "JoIPYWx0LmV4YW1wbGUub3JnhhNodHRwOi8vZXhhbXBsZS5vcmcvMBMGA1UdJQQM\n"
|
||||
+ "MAoGCCsGAQUFBwMBMB0GA1UdDgQWBBSXBONihYHHlbM9mrezDF7o607tFTANBgkq\n"
|
||||
+ "hkiG9w0BAQsFAAOCAYEAHk3bGPAl8YvQE84KZnCnVWBfayFeHKXlN/o/MvpYtPb2\n"
|
||||
+ "y9cnD8IMmruW3A/UL+md2xx24V+pQWmugB2e879N/Q3QVsSbHFlzPei4tieK5VVd\n"
|
||||
+ "gLC2iG7N8YjQ0SNRDF22A1QQDcVzdCXOggivs4MelF1zaGfY3ywHOhiHXt0jDj1o\n"
|
||||
+ "2bP5OflElDFVF7m38RDwdeGokb+raW/2lOJZe4oKpdmllyUtLvrQhdwpogwnbpvH\n"
|
||||
+ "7ln5Tq4wDNIcxM+Y4MQwe6m0AEELdFZjBmfsZthmaGrbppLTbp14rzC6kKqZ9ay/\n"
|
||||
+ "zG06DhPalDCR+Bqvmh2Qp25xgqThv9AX8JQU6W8avnkfyxFZwBEJZ0lNoOyLZV2Z\n"
|
||||
+ "4vmflZyOih9ccGUaYXWXzyc+vxNZjFQwjWNss2vynVvp4+5DUeMWeAj/unvjrxy2\n"
|
||||
+ "HOsI4FrD94g5PchhXyKXRmeJk4mcr0jtE5ycbmiDU3sXz6xM7hsdBeNFyr47L2nj\n"
|
||||
+ "OfWEK8ArBc3uTEgp2tIA\n"
|
||||
+ "-----END CERTIFICATE-----\n";
|
||||
+
|
||||
+char uri_and_cn[] =
|
||||
+ "organization = GnuTLS test\n"
|
||||
+ "expiration_days = 365\n"
|
||||
+ "tls_www_server\n"
|
||||
+ "uri = http://example.org/\n"
|
||||
+ "cn = example.org\n"
|
||||
+ "-----BEGIN CERTIFICATE-----\n"
|
||||
+ "MIIESjCCArKgAwIBAgIUNC/WOkhQZc6stg6RSrVPaUHRmLwwDQYJKoZIhvcNAQEL\n"
|
||||
+ "BQAwLDEUMBIGA1UEChMLR251VExTIHRlc3QxFDASBgNVBAMTC2V4YW1wbGUub3Jn\n"
|
||||
+ "MB4XDTI2MDMxMzE1NTAwNVoXDTI3MDMxMzE1NTAwNVowLDEUMBIGA1UEChMLR251\n"
|
||||
+ "VExTIHRlc3QxFDASBgNVBAMTC2V4YW1wbGUub3JnMIIBojANBgkqhkiG9w0BAQEF\n"
|
||||
+ "AAOCAY8AMIIBigKCAYEArEgcC7WDqNJCpO0J3UfCraRWzmwk7soTg7pMmCv1FHWP\n"
|
||||
+ "ywxfXxbl0jvRK/Owyv7q5QRdfcxSYhxydrloCOdWXhGQejgzcpgLu/Y3Ij0CjIzr\n"
|
||||
+ "C38vMSS7yUjAuzB4IYtZsgyuB+bCfGH2Y227ntuniIjEnuekA18gfFemRUQ8PDao\n"
|
||||
+ "EzNAPn8Q3cFlHh5Kr3gkDUduQlRhZdK0ryU/XaAUxz9G9TminIKCl4h1bKNT2pXN\n"
|
||||
+ "08Cg3eOEi3Bl8lCCA7ufODl5frfrDcjNkxqRKN99zMa9A9hcRzYNF9/asX+BXFyh\n"
|
||||
+ "7qbypKXAHBi6xi055+CRIBTxFC960qAluv2cOlo1tzZ0Nta75GhWCqLaVZgI0D0n\n"
|
||||
+ "6SPZPEknVjGPQx1vSnq3ZNdNDdG83yw4QjFtujXdKrflcJafCg3D6LCvEyDPBdYC\n"
|
||||
+ "reTJ9xWNCdsxdzlTdDk11CbxdIz4jA7qA/forbY9Dv7l0iC9d2zWmn4DOv23QIki\n"
|
||||
+ "Uw46/ymnpeFaUTyNyyNHAgMBAAGjZDBiMAwGA1UdEwEB/wQCMAAwHgYDVR0RBBcw\n"
|
||||
+ "FYYTaHR0cDovL2V4YW1wbGUub3JnLzATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNV\n"
|
||||
+ "HQ4EFgQUlwTjYoWBx5WzPZq3swxe6OtO7RUwDQYJKoZIhvcNAQELBQADggGBAE6w\n"
|
||||
+ "uGfQy1pi+VbvHFc64QZJhf6r0FQl8Y5kWPu7OI2o+M5/FmY9hXmXxJzAfGH3ecE8\n"
|
||||
+ "PL/bnR9zRCHTi1ONogukPKPmm/x3AQehn54hvgjZXGFOMxGBB5wSbsEzjCQxgKOO\n"
|
||||
+ "uzUKZ0zgJin5YEi9g3DGKYi1qDNceNB9LjsWq372FKze0y2zZT7U2xiQcXlKgIZ6\n"
|
||||
+ "KEcRBQVDygKNeU8ux0Q+lSaymsT9dhs6uahmGUTbbLcsKxsPhJjfC3IWTH+vK3tV\n"
|
||||
+ "yjjnHcfcITAYSYHOM8+2+5EMOCZmGxCqv3unDkJRYY2xrp3+kXyGXXKRw+yNs4MT\n"
|
||||
+ "Zc9zymseS+rB+9SDYO4DHDIV+jMJPMcqjJSlglMhs53Z4HFuWcuYJ6FzbRyM7hky\n"
|
||||
+ "X4El+DWVaajh10QZApiWnRTTafJzJTbYljbpdZVgDX6chAyQRTKj6Di7YrrXmlYZ\n"
|
||||
+ "iPKiHBqRUnCnxe8HYoBeK5Dw1lzCmgqXp5wjRqo5UHaemgZQTjdlPiWeovEiVg==\n"
|
||||
+ "-----END CERTIFICATE-----\n";
|
||||
+
|
||||
+char srv_and_cn[] =
|
||||
+ "-----BEGIN CERTIFICATE-----\n"
|
||||
+ "MIIESjCCArKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAsMRQwEgYDVQQKEwtHbnVU\n"
|
||||
+ "TFMgdGVzdDEUMBIGA1UEAxMLZXhhbXBsZS5vcmcwHhcNMjYwMzEzMTY0OTU5WhcN\n"
|
||||
+ "MjcwMzEzMTY0OTU5WjAsMRQwEgYDVQQKEwtHbnVUTFMgdGVzdDEUMBIGA1UEAxML\n"
|
||||
+ "ZXhhbXBsZS5vcmcwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCsSBwL\n"
|
||||
+ "tYOo0kKk7QndR8KtpFbObCTuyhODukyYK/UUdY/LDF9fFuXSO9Er87DK/urlBF19\n"
|
||||
+ "zFJiHHJ2uWgI51ZeEZB6ODNymAu79jciPQKMjOsLfy8xJLvJSMC7MHghi1myDK4H\n"
|
||||
+ "5sJ8YfZjbbue26eIiMSe56QDXyB8V6ZFRDw8NqgTM0A+fxDdwWUeHkqveCQNR25C\n"
|
||||
+ "VGFl0rSvJT9doBTHP0b1OaKcgoKXiHVso1Palc3TwKDd44SLcGXyUIIDu584OXl+\n"
|
||||
+ "t+sNyM2TGpEo333Mxr0D2FxHNg0X39qxf4FcXKHupvKkpcAcGLrGLTnn4JEgFPEU\n"
|
||||
+ "L3rSoCW6/Zw6WjW3NnQ21rvkaFYKotpVmAjQPSfpI9k8SSdWMY9DHW9Kerdk100N\n"
|
||||
+ "0bzfLDhCMW26Nd0qt+Vwlp8KDcPosK8TIM8F1gKt5Mn3FY0J2zF3OVN0OTXUJvF0\n"
|
||||
+ "jPiMDuoD9+ittj0O/uXSIL13bNaafgM6/bdAiSJTDjr/Kael4VpRPI3LI0cCAwEA\n"
|
||||
+ "AaN3MHUwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4E\n"
|
||||
+ "FgQUlwTjYoWBx5WzPZq3swxe6OtO7RUwMQYDVR0RBCowKKAmBggrBgEFBQcIB6Aa\n"
|
||||
+ "FhhfeG1wcC1jbGllbnQuZXhhbXBsZS5vcmcwDQYJKoZIhvcNAQELBQADggGBAI0B\n"
|
||||
+ "WAylO7fWCLtWJqfMrHa3JFH2rkQRf5WV+Z5JqcxlP47m6220+xBiV/iIZT0V6Un/\n"
|
||||
+ "Z/4Je+jrx6vFIAxtTR1gmyfLo8TfzkEmwPT+uHb16RFkJbi5ik47Mm+31VOrq2G/\n"
|
||||
+ "s1FP0oNCG6LAnVN1a3Np5uorbUJlTkrd9MxymIvbZMQ56pZvI8TeNgescxD3xY96\n"
|
||||
+ "/yQXFBy3wu8PIJblG/7r5vPSY8BrEqpRZ0Dch4EoU2RVybE0vXUUTL2moripnHzF\n"
|
||||
+ "4+mm4Fa8mNb6nII8RjmFDJJzKCQlpmm4R8iNaCvULv8jVO899XUwDSL8+hHt6jZK\n"
|
||||
+ "aU0pWVCorxpUmgQiQmBAIYvreSM4nKtljSwT2+SBaMna+MaZk2vfBDO15tZH0LWW\n"
|
||||
+ "OYpnqQQkihP9my4jESvn8FE4NtF5x44XuJVKTVSas1o49XLXq/94fT4DZGa6rdSx\n"
|
||||
+ "p9Nnj64WFIqbTLoqM3nt7+zqFZDvwh+8ZEVcE1MazHOYhDQj1uU3jqIq/sZE8w==\n"
|
||||
+ "-----END CERTIFICATE-----\n";
|
||||
+
|
||||
|
||||
void doit(void)
|
||||
{
|
||||
@@ -1214,6 +1307,54 @@ void doit(void)
|
||||
|
||||
gnutls_openpgp_crt_deinit(pgp);
|
||||
#endif
|
||||
+
|
||||
+ if (debug)
|
||||
+ success("Testing not falling back to CN with DNS+URI SAN...\n");
|
||||
+ data.data = (unsigned char *)dns_uri_and_cn;
|
||||
+ data.size = strlen(dns_uri_and_cn);
|
||||
+
|
||||
+ ret = gnutls_x509_crt_import(x509, &data, GNUTLS_X509_FMT_PEM);
|
||||
+ if (ret < 0)
|
||||
+ fail("%d: gnutls_x509_crt_import: %d\n", __LINE__, ret);
|
||||
+
|
||||
+ ret = gnutls_x509_crt_check_hostname(x509, "example.org");
|
||||
+ if (ret)
|
||||
+ fail("%d: Hostname incorrectly falls back to CN (%d)\n",
|
||||
+ __LINE__, ret);
|
||||
+
|
||||
+ ret = gnutls_x509_crt_check_hostname(x509, "alt.example.org");
|
||||
+ if (!ret)
|
||||
+ fail("%d: Hostname does not match a valid DNS SAN (%d)\n",
|
||||
+ __LINE__, ret);
|
||||
+
|
||||
+ if (debug)
|
||||
+ success("Testing not falling back to CN with URI SAN...\n");
|
||||
+ data.data = (unsigned char *)uri_and_cn;
|
||||
+ data.size = strlen(uri_and_cn);
|
||||
+
|
||||
+ ret = gnutls_x509_crt_import(x509, &data, GNUTLS_X509_FMT_PEM);
|
||||
+ if (ret < 0)
|
||||
+ fail("%d: gnutls_x509_crt_import: %d\n", __LINE__, ret);
|
||||
+
|
||||
+ ret = gnutls_x509_crt_check_hostname(x509, "example.org");
|
||||
+ if (ret)
|
||||
+ fail("%d: Hostname incorrectly falls back to CN (%d)\n",
|
||||
+ __LINE__, ret);
|
||||
+
|
||||
+ if (debug)
|
||||
+ success("Testing not falling back to CN with SRV SAN...\n");
|
||||
+ data.data = (unsigned char *)srv_and_cn;
|
||||
+ data.size = strlen(srv_and_cn);
|
||||
+
|
||||
+ ret = gnutls_x509_crt_import(x509, &data, GNUTLS_X509_FMT_PEM);
|
||||
+ if (ret < 0)
|
||||
+ fail("%d: gnutls_x509_crt_import: %d\n", __LINE__, ret);
|
||||
+
|
||||
+ ret = gnutls_x509_crt_check_hostname(x509, "example.org");
|
||||
+ if (ret)
|
||||
+ fail("%d: Hostname incorrectly falls back to CN (%d)\n",
|
||||
+ __LINE__, ret);
|
||||
+
|
||||
gnutls_x509_crt_deinit(x509);
|
||||
|
||||
gnutls_global_deinit();
|
||||
--
|
||||
2.53.0
|
||||
|
||||
244
SOURCES/gnutls-3.6.16-CVE-2026-42013-oversized-san.patch
Normal file
244
SOURCES/gnutls-3.6.16-CVE-2026-42013-oversized-san.patch
Normal file
@ -0,0 +1,244 @@
|
||||
From 3ee2cb707002f755e4bda3f75285caa0cb36c214 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Wed, 15 Apr 2026 15:35:59 +0200
|
||||
Subject: [PATCH 1/3] x509/email-verify: call fallback DN fallback
|
||||
|
||||
A comment was inaccurately referring to DN email field fallback
|
||||
as CN fallback.
|
||||
Rename a few things as well to match x509/hostname-verify more closely.
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/x509/email-verify.c | 12 +++++-------
|
||||
1 file changed, 5 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/lib/x509/email-verify.c b/lib/x509/email-verify.c
|
||||
index 053e51287..0d55e5524 100644
|
||||
--- a/lib/x509/email-verify.c
|
||||
+++ b/lib/x509/email-verify.c
|
||||
@@ -43,7 +43,7 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert,
|
||||
{
|
||||
char rfc822name[MAX_CN];
|
||||
size_t rfc822namesize;
|
||||
- int found_rfc822name = 0;
|
||||
+ bool dn_fallback_allowed = true;
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
char *a_email;
|
||||
@@ -79,7 +79,7 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert,
|
||||
NULL);
|
||||
|
||||
if (ret == GNUTLS_SAN_RFC822NAME) {
|
||||
- found_rfc822name = 1;
|
||||
+ dn_fallback_allowed = false;
|
||||
|
||||
if (_gnutls_has_embedded_null(rfc822name, rfc822namesize)) {
|
||||
_gnutls_debug_log("certificate has %s with embedded null in rfc822name\n", rfc822name);
|
||||
@@ -99,12 +99,10 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert,
|
||||
}
|
||||
}
|
||||
|
||||
- if (!found_rfc822name) {
|
||||
- /* did not get the necessary extension, use CN instead
|
||||
- */
|
||||
+ if (dn_fallback_allowed) {
|
||||
+ /* did not get the necessary extension, use DN email instead */
|
||||
|
||||
- /* enforce the RFC6125 (§1.8) requirement that only
|
||||
- * a single CN must be present */
|
||||
+ /* only a single one must be present */
|
||||
rfc822namesize = sizeof(rfc822name);
|
||||
ret = gnutls_x509_crt_get_dn_by_oid
|
||||
(cert, GNUTLS_OID_PKCS9_EMAIL, 1, 0, rfc822name,
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 29801bef00ecc0f23c0bac4cd333b269cd2c1af4 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Wed, 15 Apr 2026 16:02:19 +0200
|
||||
Subject: [PATCH 2/3] x509: prevent fallback on oversized SAN
|
||||
|
||||
Passing oversized SAN did not preclude CN (or DN email) fallback
|
||||
during verification, which is an RFC 6125 6.4.4 violation.
|
||||
|
||||
Now oversized SAN are skipped over,
|
||||
but prevent the fallback from happening.
|
||||
|
||||
Reported-by: Haruto Kimura (Stella)
|
||||
Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
|
||||
Fixes: #1825
|
||||
Fixes: #1849
|
||||
Fixes: CVE-2026-42013
|
||||
Fixes: GNUTLS-SA-2026-04-27-8
|
||||
CVSS: 6.5 Moderate CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:N
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/x509/email-verify.c | 14 ++++++++++++++
|
||||
lib/x509/hostname-verify.c | 14 ++++++++++++++
|
||||
2 files changed, 28 insertions(+)
|
||||
|
||||
diff --git a/lib/x509/email-verify.c b/lib/x509/email-verify.c
|
||||
index 0d55e5524..f755d766e 100644
|
||||
--- a/lib/x509/email-verify.c
|
||||
+++ b/lib/x509/email-verify.c
|
||||
@@ -78,6 +78,20 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert,
|
||||
&rfc822namesize,
|
||||
NULL);
|
||||
|
||||
+ if (ret < 0) {
|
||||
+ if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
|
||||
+ /* oversized SAN; proceed without DN fallback */
|
||||
+ _gnutls_debug_log("oversized SAN ignored, "
|
||||
+ "disabling DN fallback\n");
|
||||
+ dn_fallback_allowed = false;
|
||||
+ ret = 0;
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
|
||||
+ gnutls_assert();
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
if (ret == GNUTLS_SAN_RFC822NAME) {
|
||||
dn_fallback_allowed = false;
|
||||
|
||||
diff --git a/lib/x509/hostname-verify.c b/lib/x509/hostname-verify.c
|
||||
index d46fd965f..6d6de00ca 100644
|
||||
--- a/lib/x509/hostname-verify.c
|
||||
+++ b/lib/x509/hostname-verify.c
|
||||
@@ -218,6 +218,20 @@ gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
|
||||
&dnsnamesize,
|
||||
NULL);
|
||||
|
||||
+ if (ret < 0) {
|
||||
+ if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
|
||||
+ /* oversized SAN; proceed without CN fallback */
|
||||
+ _gnutls_debug_log("oversized SAN ignored, "
|
||||
+ "disabling CN fallback\n");
|
||||
+ cn_fallback_allowed = false;
|
||||
+ ret = 0;
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
|
||||
+ gnutls_assert();
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
if (PRECLUDES_CN_FALLBACK(ret))
|
||||
cn_fallback_allowed = false;
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 01a4fd98b5b85f6736333aa0381bb56c9aa8dbb9 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Wed, 15 Apr 2026 18:02:31 +0200
|
||||
Subject: [PATCH 3/3] tests/cert-tests: add tests for #1825
|
||||
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
.../cert-tests/email-certs/oversized-san.pem | 16 +++++++++
|
||||
tests/cert-tests/email | 11 +++++++
|
||||
tests/hostname-check.c | 33 +++++++++++++++++++
|
||||
3 files changed, 60 insertions(+)
|
||||
create mode 100644 tests/cert-tests/email-certs/oversized-san.pem
|
||||
|
||||
diff --git a/tests/cert-tests/email-certs/oversized-san.pem b/tests/cert-tests/email-certs/oversized-san.pem
|
||||
new file mode 100644
|
||||
index 000000000..44c0f6997
|
||||
--- /dev/null
|
||||
+++ b/tests/cert-tests/email-certs/oversized-san.pem
|
||||
@@ -0,0 +1,16 @@
|
||||
+-----BEGIN CERTIFICATE-----
|
||||
+MIICezCCAi2gAwIBAgIUWECpllJihTypDAKZQgEJeM02fG8wBQYDK2VwMDcxFDAS
|
||||
+BgNVBAMTC2V4YW1wbGUuY29tMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUu
|
||||
+Y29tMB4XDTI2MDQxNTE1NTE1MloXDTI3MDQxNTE1NTE1MlowNzEUMBIGA1UEAxML
|
||||
+ZXhhbXBsZS5jb20xHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wKjAF
|
||||
+BgMrZXADIQCn95fhASNNgr5I/qAX+kiY8SiwPJcTVy1ugWJdX3d4uqOCAUkwggFF
|
||||
+MA8GA1UdEwEB/wQFMAMBAf8wggERBgNVHREEggEIMIIBBIGCAQBhYWFhYWFhYWFh
|
||||
+YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh
|
||||
+YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh
|
||||
+YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh
|
||||
+YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh
|
||||
+YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh
|
||||
+YWFhYWFhMB0GA1UdDgQWBBTeT2MAM29EwVLvTom8wGN05B7QhDAFBgMrZXADQQAQ
|
||||
+zTZqdt4LXX21VFce7S99k6XX+N+xPAUo4beursVrlaesdVsfvDtEk2t+0b5WLbtW
|
||||
+7UI9PxB9CN4hULrxrI8N
|
||||
+-----END CERTIFICATE-----
|
||||
diff --git a/tests/cert-tests/email b/tests/cert-tests/email
|
||||
index a00281028..d2bd48ee3 100755
|
||||
--- a/tests/cert-tests/email
|
||||
+++ b/tests/cert-tests/email
|
||||
@@ -96,5 +96,16 @@ if test "${rc}" != "1"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
+# #1825: oversized SAN does not preclude fallback to DN email
|
||||
+${VALGRIND} "${CERTTOOL}" \
|
||||
+ --infile "${srcdir}/email-certs/oversized-san.pem" \
|
||||
+ --load-ca-certificate "${srcdir}/email-certs/oversized-san.pem" \
|
||||
+ --verify --verify-email test@example.com
|
||||
+rc=$?
|
||||
+
|
||||
+if test "${rc}" != "1"; then
|
||||
+ echo "email test 9 failed"
|
||||
+ exit 1
|
||||
+fi
|
||||
|
||||
exit 0
|
||||
diff --git a/tests/hostname-check.c b/tests/hostname-check.c
|
||||
index 71481cafb..068bf7831 100644
|
||||
--- a/tests/hostname-check.c
|
||||
+++ b/tests/hostname-check.c
|
||||
@@ -924,6 +924,24 @@ char srv_and_cn[] =
|
||||
"p9Nnj64WFIqbTLoqM3nt7+zqFZDvwh+8ZEVcE1MazHOYhDQj1uU3jqIq/sZE8w==\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
+char pem_1825_oversized_san[] =
|
||||
+ "ca\n"
|
||||
+ "cn = example.com\n"
|
||||
+ "dns_name = <'a' * 256>\n"
|
||||
+ "-----BEGIN CERTIFICATE-----\n"
|
||||
+ "MIICOTCCAeugAwIBAgIURFygaiK3EBmc5AMZToFitMMikhcwBQYDK2VwMBYxFDAS\n"
|
||||
+ "BgNVBAMTC2V4YW1wbGUuY29tMB4XDTI2MDQxNTE2MDYwMFoXDTI3MDQxNTE2MDYw\n"
|
||||
+ "MFowFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wKjAFBgMrZXADIQBHqgbjhT1zZ3h9\n"
|
||||
+ "okSrhd2+0Lr0Uj1q81sqHrcCEdqVpaOCAUkwggFFMA8GA1UdEwEB/wQFMAMBAf8w\n"
|
||||
+ "ggERBgNVHREEggEIMIIBBIKCAQBhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh\n"
|
||||
+ "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh\n"
|
||||
+ "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh\n"
|
||||
+ "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh\n"
|
||||
+ "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh\n"
|
||||
+ "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhMB0GA1UdDgQWBBT+\n"
|
||||
+ "/oWt1Lrfz7Awk9h8yDoz1TKyHjAFBgMrZXADQQBfR5ByQyxpLEsVM5+ihYjSbmYF\n"
|
||||
+ "1pOFndq0UIKPkWsRqBpitzDIVrVTLlIcY0fQpsxITNgdoIU68WynLGVrRHIF\n"
|
||||
+ "-----END CERTIFICATE-----\n";
|
||||
|
||||
void doit(void)
|
||||
{
|
||||
@@ -1355,6 +1373,21 @@ void doit(void)
|
||||
fail("%d: Hostname incorrectly falls back to CN (%d)\n",
|
||||
__LINE__, ret);
|
||||
|
||||
+ if (debug)
|
||||
+ success("Testing oversized SAN (#1825)...\n");
|
||||
+ data.data = (unsigned char *)pem_1825_oversized_san;
|
||||
+ data.size = strlen(pem_1825_oversized_san);
|
||||
+
|
||||
+ ret = gnutls_x509_crt_import(x509, &data, GNUTLS_X509_FMT_PEM);
|
||||
+ if (ret < 0)
|
||||
+ fail("%d: gnutls_x509_crt_import: %d\n", __LINE__, ret);
|
||||
+
|
||||
+ ret = gnutls_x509_crt_check_hostname(x509, "example.com");
|
||||
+ if (ret)
|
||||
+ fail("%d: Hostname incorrectly falls back to CN "
|
||||
+ "with oversized SAN (%d)\n",
|
||||
+ __LINE__, ret);
|
||||
+
|
||||
gnutls_x509_crt_deinit(x509);
|
||||
|
||||
gnutls_global_deinit();
|
||||
--
|
||||
2.53.0
|
||||
|
||||
60
SOURCES/gnutls-3.6.16-CVE-2026-42014-so-pin-uaf.patch
Normal file
60
SOURCES/gnutls-3.6.16-CVE-2026-42014-so-pin-uaf.patch
Normal file
@ -0,0 +1,60 @@
|
||||
From 3957f136e2ed23caf176a594b54b3827f5cef701 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Wed, 18 Mar 2026 18:19:06 +0100
|
||||
Subject: [PATCH] pkcs11_write: fix UAF and leak in gnutls_pkcs11_token_set_pin
|
||||
|
||||
Changing Security Officer PIN with gnutls_pkcs11_token_set_pin() with
|
||||
oldpin == NULL for a token that lacks a protected authentication path
|
||||
led to a use-after-free.
|
||||
|
||||
Reported-by: Luigino Camastra and Joshua Rogers of AISLE Research Team
|
||||
Fixes: #1766
|
||||
Fixes: #1809
|
||||
Fixes: CVE-2026-42014
|
||||
Fixes: GNUTLS-SA-2026-04-29-9
|
||||
CVSS: 4.0 Medium CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/pkcs11_write.c | 10 ++++++----
|
||||
1 file changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/lib/pkcs11_write.c b/lib/pkcs11_write.c
|
||||
index 5685411ee..194126e95 100644
|
||||
--- a/lib/pkcs11_write.c
|
||||
+++ b/lib/pkcs11_write.c
|
||||
@@ -1297,10 +1297,9 @@ gnutls_pkcs11_token_set_pin(const char *token_url,
|
||||
ses_flags = SESSION_WRITE | SESSION_LOGIN;
|
||||
|
||||
ret = pkcs11_open_session(&sinfo, NULL, info, ses_flags);
|
||||
- p11_kit_uri_free(info);
|
||||
-
|
||||
if (ret < 0) {
|
||||
gnutls_assert();
|
||||
+ p11_kit_uri_free(info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1322,8 +1321,10 @@ gnutls_pkcs11_token_set_pin(const char *token_url,
|
||||
oldpin_size = L(oldpin);
|
||||
|
||||
if (!(sinfo.tinfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH)) {
|
||||
- if (newpin == NULL)
|
||||
- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
||||
+ if (newpin == NULL) {
|
||||
+ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
||||
+ goto finish;
|
||||
+ }
|
||||
|
||||
if (oldpin == NULL) {
|
||||
struct pin_info_st pin_info;
|
||||
@@ -1354,6 +1355,7 @@ gnutls_pkcs11_token_set_pin(const char *token_url,
|
||||
ret = 0;
|
||||
|
||||
finish:
|
||||
+ p11_kit_uri_free(info);
|
||||
pkcs11_close_session(&sinfo);
|
||||
return ret;
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
44
SOURCES/gnutls-3.6.16-CVE-2026-42015-p12-bag32.patch
Normal file
44
SOURCES/gnutls-3.6.16-CVE-2026-42015-p12-bag32.patch
Normal file
@ -0,0 +1,44 @@
|
||||
From a3e7c50d3e1761e5ef1d4b225507cab8f2b2c3ca Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 20 Apr 2026 22:42:20 +0200
|
||||
Subject: [PATCH] x509/pkcs12_bag: fix off-by-one in bag element bounds check
|
||||
|
||||
Appending elements to a PKCS#12 bag had a bounds check that
|
||||
prevented adding the 32nd element.
|
||||
On the other hand, it is possible to import one that already has 32.
|
||||
Subsequent appending then led to writing past the 32-element array,
|
||||
smashing its length.
|
||||
|
||||
Tighten the check to reject any bag with 32 or more elements.
|
||||
|
||||
We'll treat this vulnerability as a Low due to how contrived
|
||||
the requirements are: for the code to be vulnerable,
|
||||
it needs to append to an imported untrusted unencrypted PKCS#12 structure.
|
||||
|
||||
Reported-by: Zou Dikai
|
||||
Fixes: #1840
|
||||
Fixes: CVE-2026-42015
|
||||
Fixes: GNUTLS-SA-2026-04-29-11
|
||||
CVSS: 6.1 Medium CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:H
|
||||
Severity: Low
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/x509/pkcs12_bag.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/x509/pkcs12_bag.c b/lib/x509/pkcs12_bag.c
|
||||
index 163b0fadb..351996b2f 100644
|
||||
--- a/lib/x509/pkcs12_bag.c
|
||||
+++ b/lib/x509/pkcs12_bag.c
|
||||
@@ -394,7 +394,7 @@ gnutls_pkcs12_bag_set_data(gnutls_pkcs12_bag_t bag,
|
||||
return GNUTLS_E_INVALID_REQUEST;
|
||||
}
|
||||
|
||||
- if (bag->bag_elements == MAX_BAG_ELEMENTS - 1) {
|
||||
+ if (bag->bag_elements >= MAX_BAG_ELEMENTS - 1) {
|
||||
gnutls_assert();
|
||||
/* bag is full */
|
||||
return GNUTLS_E_MEMORY_ERROR;
|
||||
--
|
||||
2.53.0
|
||||
|
||||
107
SOURCES/gnutls-3.6.16-CVE-2026-5260-p11-rsa-overread.patch
Normal file
107
SOURCES/gnutls-3.6.16-CVE-2026-5260-p11-rsa-overread.patch
Normal file
@ -0,0 +1,107 @@
|
||||
From 77228f2d1ac207d2f894e5a168fbb47e5378e42f Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 30 Mar 2026 17:31:07 +0200
|
||||
Subject: [PATCH 1/2] lib/auth/rsa: check that ciphertext matches the modulus
|
||||
size
|
||||
|
||||
A client sending extremely short premaster secret as part of an
|
||||
RSA key exchange could've theoretically triggered a short heap overread
|
||||
to nowhere when the RSA key was backed with a PKCS#11 token.
|
||||
With this fix, the internal decryption function will not be called
|
||||
with an mismatching plaintext length specified, avoiding the overread.
|
||||
|
||||
Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
|
||||
Fixes: #1814
|
||||
Fixes: CVE-2026-5260
|
||||
Fixes: GNUTLS-SA-2026-04-29-10
|
||||
CVSS: 5.9 Medium CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/auth/rsa.c | 5 +++++
|
||||
lib/auth/rsa_psk.c | 5 +++++
|
||||
2 files changed, 10 insertions(+)
|
||||
|
||||
diff --git a/lib/auth/rsa.c b/lib/auth/rsa.c
|
||||
index 02b6a3425..b2665d3af 100644
|
||||
--- a/lib/auth/rsa.c
|
||||
+++ b/lib/auth/rsa.c
|
||||
@@ -159,6 +159,7 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data,
|
||||
int ret, dsize;
|
||||
ssize_t data_size = _data_size;
|
||||
volatile uint8_t ver_maj, ver_min;
|
||||
+ unsigned int key_bits;
|
||||
|
||||
#ifdef ENABLE_SSL3
|
||||
if (get_num_version(session) == GNUTLS_SSL3) {
|
||||
@@ -181,6 +182,10 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data,
|
||||
}
|
||||
ciphertext.size = dsize;
|
||||
}
|
||||
+ gnutls_privkey_get_pk_algorithm(session->internals.selected_key,
|
||||
+ &key_bits);
|
||||
+ if (ciphertext.size != (key_bits + 7) / 8)
|
||||
+ return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
|
||||
|
||||
ver_maj = _gnutls_get_adv_version_major(session);
|
||||
ver_min = _gnutls_get_adv_version_minor(session);
|
||||
diff --git a/lib/auth/rsa_psk.c b/lib/auth/rsa_psk.c
|
||||
index 8813eeeec..7768b60f2 100644
|
||||
--- a/lib/auth/rsa_psk.c
|
||||
+++ b/lib/auth/rsa_psk.c
|
||||
@@ -270,6 +270,7 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
|
||||
ssize_t data_size = _data_size;
|
||||
gnutls_psk_server_credentials_t cred;
|
||||
volatile uint8_t ver_maj, ver_min;
|
||||
+ unsigned int rsa_key_bits;
|
||||
|
||||
cred = (gnutls_psk_server_credentials_t)
|
||||
_gnutls_get_cred(session, GNUTLS_CRD_PSK);
|
||||
@@ -324,6 +325,10 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
|
||||
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
|
||||
}
|
||||
ciphertext.size = dsize;
|
||||
+ gnutls_privkey_get_pk_algorithm(session->internals.selected_key,
|
||||
+ &rsa_key_bits);
|
||||
+ if (ciphertext.size != (rsa_key_bits + 7) / 8)
|
||||
+ return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
|
||||
|
||||
ver_maj = _gnutls_get_adv_version_major(session);
|
||||
ver_min = _gnutls_get_adv_version_minor(session);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From cf6bdc5e4df49e5583d3fb4d2296779785f10683 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
Date: Mon, 30 Mar 2026 17:46:40 +0200
|
||||
Subject: [PATCH 2/2] lib/pkcs11_privkey: guard against overreading on short
|
||||
ciphertexts
|
||||
|
||||
This is an alternative fix for the callee side.
|
||||
|
||||
Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
|
||||
Fixes: #1814
|
||||
Fixes: CVE-2026-5260
|
||||
Fixes: GNUTLS-SA-2026-04-29-10
|
||||
CVSS: 5.9 Medium CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
---
|
||||
lib/pkcs11_privkey.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c
|
||||
index 3ecd1837b..334132ef3 100644
|
||||
--- a/lib/pkcs11_privkey.c
|
||||
+++ b/lib/pkcs11_privkey.c
|
||||
@@ -769,7 +769,7 @@ _gnutls_pkcs11_privkey_decrypt_data2(gnutls_pkcs11_privkey_t key,
|
||||
if (ret != 0)
|
||||
return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR);
|
||||
|
||||
- buffer = gnutls_malloc(siglen);
|
||||
+ buffer = gnutls_malloc(MAX((size_t)siglen, plaintext_size));
|
||||
if (!buffer) {
|
||||
gnutls_assert();
|
||||
return GNUTLS_E_MEMORY_ERROR;
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
Version: 3.6.16
|
||||
Release: 8%{?dist}.5
|
||||
Release: 8%{?dist}.6
|
||||
Patch1: gnutls-3.2.7-rpath.patch
|
||||
Patch2: gnutls-3.6.4-no-now-guile.patch
|
||||
Patch3: gnutls-3.6.13-enable-intel-cet.patch
|
||||
@ -21,6 +21,33 @@ Patch24: gnutls-3.6.16-cve-2025-32988.patch
|
||||
Patch25: gnutls-3.6.16-cve-2025-32990.patch
|
||||
Patch26: gnutls-3.6.16-CVE-2025-9820.patch
|
||||
Patch27: gnutls-3.6.16-CVE-2025-14831.patch
|
||||
# CVE fixes backported from 3.8.13 release
|
||||
# (https://gitlab.com/gnutls/gnutls/-/merge_requests/2102)
|
||||
Patch28: gnutls-3.6.16-CVE-2026-33846-dtls-len.patch
|
||||
Patch29: gnutls-3.6.16-CVE-2026-42009-dtls-qsort.patch
|
||||
Patch30: gnutls-3.6.16-CVE-2026-33845-dtls-uflow.patch
|
||||
Patch31: gnutls-3.6.16-CVE-2026-42010-psk-nul.patch
|
||||
Patch32: gnutls-3.6.16-CVE-2026-3833-nc-case.patch
|
||||
Patch33: gnutls-3.6.16-CVE-2026-42011-nc-intersect.patch
|
||||
Patch34: gnutls-3.6.16-CVE-2026-42012-url-san-cn.patch
|
||||
Patch35: gnutls-3.6.16-CVE-2026-42013-oversized-san.patch
|
||||
Patch36: gnutls-3.6.16-CVE-2026-42014-so-pin-uaf.patch
|
||||
Patch37: gnutls-3.6.16-CVE-2026-5260-p11-rsa-overread.patch
|
||||
Patch38: gnutls-3.6.16-CVE-2026-42015-p12-bag32.patch
|
||||
# not in 3.6: CVE-2026-3832-ocsp-rev-0 - since 3.8.9
|
||||
# not in 3.6: CVE-2026-5419-p7-constant-time - since 3.7.7
|
||||
# non-CVE security fixes from the same release
|
||||
Patch39: gnutls-3.6.16-1808-psk-rehandshake.patch
|
||||
Patch40: gnutls-3.6.16-1810-ocsp-truncated-eku.patch
|
||||
# not in 3.6: 1813-p11p-aes-ephemeral
|
||||
Patch41: gnutls-3.6.16-1818-rsa-coprime.patch
|
||||
Patch42: gnutls-3.6.16-1818-pem-parsing.patch
|
||||
Patch43: gnutls-3.6.16-1819-dblfree-mid-import.patch
|
||||
# not in 3.6: 1822-sct-overread
|
||||
# not in 3.6: 1823-cfg-clear-options
|
||||
Patch44: gnutls-3.6.16-1817-security-parameters.patch
|
||||
# not in 3.6: 1820-p11p-kdf
|
||||
|
||||
%bcond_without dane
|
||||
%if 0%{?rhel}
|
||||
%bcond_with guile
|
||||
@ -235,7 +262,7 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/pkgconfig/gnutls-dane.pc
|
||||
%find_lang gnutls
|
||||
|
||||
%check
|
||||
make check %{?_smp_mflags}
|
||||
make check %{?_smp_mflags} V=1 VERBOSE=1
|
||||
|
||||
%post devel
|
||||
if [ -f %{_infodir}/gnutls.info.gz ]; then
|
||||
@ -305,6 +332,24 @@ fi
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Thu Apr 30 2026 Alexander Sosedkin <asosedkin@redhat.com> - 3.6.16-8.6
|
||||
- Fix CVE-2026-33846 (DTLS fragment reassembly, High, heap overwrite)
|
||||
- Fix CVE-2026-42009 (DTLS fragment reassembly, High, undefined behaviour)
|
||||
- Fix CVE-2026-33845 (DTLS fragment reassembly, High, heap overread)
|
||||
- Fix CVE-2026-42010 (PSK authentication, High, authentication bypass)
|
||||
- Fix CVE-2026-3833 (Name constraints, Medium, name constraint bypass)
|
||||
- Fix CVE-2026-42011 (Name constraints, Medium, name constraint bypass)
|
||||
- Fix CVE-2026-42012 (CN fallback, Medium, certificate misuse)
|
||||
- Fix CVE-2026-42013 (CN fallback, Medium, certificate misuse)
|
||||
- Fix CVE-2026-42014 (PKCS#11 PIN change, Medium, use-after-free)
|
||||
- Fix CVE-2026-5260 (PKCS#11 RSA, Medium, heap overread)
|
||||
- Fix CVE-2026-42015 (PKCS#12 appending, Low, heap overwrite)
|
||||
- Fix upstream security issue #1808 (PSK rehandshake)
|
||||
- Fix upstream security issue #1810 (EKU OID prefix match)
|
||||
- Fix upstream security issue #1818 (RSA correctness, OpenSSL format import)
|
||||
- Fix upstream security issue #1819 (PKCS#11 trust removal error path)
|
||||
- Fix upstream security issue #1817 (session parameter loading robustness)
|
||||
|
||||
* Thu Feb 12 2026 Alexander Sosedkin <asosedki@redhat.com> - 3.6.16-8.5
|
||||
- Backport the fixes for CVE-2025-9820 and CVE-2025-14831
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user