Compare commits

...

No commits in common. "c8" and "c9-beta" have entirely different histories.
c8 ... c9-beta

50 changed files with 7932 additions and 20433 deletions

7
.gitignore vendored
View File

@ -1,3 +1,4 @@
SOURCES/gnutls-3.6.16.tar.xz
SOURCES/gnutls-3.6.16.tar.xz.sig
SOURCES/gpgkey-462225C3B46F34879FC8496CD605848ED7E69871.gpg
SOURCES/gmp-6.2.1.tar.xz
SOURCES/gnutls-3.8.10.tar.xz
SOURCES/gnutls-3.8.10.tar.xz.sig
SOURCES/leancrypto-1.5.0.tar.gz

View File

@ -1,3 +1,4 @@
6ba8fb898dcf4b4046b60662ba97df835593e687 SOURCES/gnutls-3.6.16.tar.xz
b41ac56ff6cca4539c8b084db2c84e8bc21d60ac SOURCES/gnutls-3.6.16.tar.xz.sig
648ec46f9539fe756fb90131b85ae4759ed2ed21 SOURCES/gpgkey-462225C3B46F34879FC8496CD605848ED7E69871.gpg
0578d48607ec0e272177d175fd1807c30b00fdf2 SOURCES/gmp-6.2.1.tar.xz
cdd236faa328ac3ad9c80a1c745461a75dcbc41b SOURCES/gnutls-3.8.10.tar.xz
adfe4a10d0a148ac7bd4b183d2d33ce23c428901 SOURCES/gnutls-3.8.10.tar.xz.sig
749aad01194f16924737d354711a9978471bdad8 SOURCES/leancrypto-1.5.0.tar.gz

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,204 +0,0 @@
From f09b7627a63defb1c55e9965fb05e0bbddb90247 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Tue, 6 Oct 2020 11:54:21 +0200
Subject: [PATCH] fips: use larger prime for DH self-tests
According to FIPS140-2 IG 7.5, the minimum key size of FFC through
2030 is defined as 2048 bits. This updates the relevant self-test
using ffdhe3072 defined in RFC 7919.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/crypto-selftests-pk.c | 142 ++++++++++++++++++++++++++++++++++----
lib/dh-primes.c | 4 --
2 files changed, 130 insertions(+), 16 deletions(-)
diff --git a/lib/crypto-selftests-pk.c b/lib/crypto-selftests-pk.c
index 70b0f618f..9b7c692a8 100644
--- a/lib/crypto-selftests-pk.c
+++ b/lib/crypto-selftests-pk.c
@@ -620,32 +620,150 @@ static int test_dh(void)
gnutls_pk_params_st priv;
gnutls_pk_params_st pub;
gnutls_datum_t out = {NULL, 0};
+
+ /* FFDHE 3072 test vector provided by Stephan Mueller in:
+ * https://gitlab.com/gnutls/gnutls/-/merge_requests/1342#note_424430996
+ */
static const uint8_t known_dh_k[] = {
- 0x10, 0x25, 0x04, 0xb5, 0xc6, 0xc2, 0xcb,
- 0x0c, 0xe9, 0xc5, 0x58, 0x0d, 0x22, 0x62};
- static const uint8_t test_p[] = {
- 0x24, 0x85, 0xdd, 0x3a, 0x74, 0x42, 0xe4,
- 0xb3, 0xf1, 0x0b, 0x13, 0xf9, 0x17, 0x4d };
- static const uint8_t test_g[] = { 0x02 };
+ 0xec, 0xb3, 0x85, 0x0c, 0x72, 0x55, 0x55, 0xc2, 0x98, 0x36,
+ 0xbe, 0x75, 0x9e, 0xc9, 0x9d, 0x8b, 0x16, 0xa6, 0xe6, 0x84,
+ 0x33, 0x12, 0x80, 0x1d, 0xac, 0xde, 0x6a, 0xd7, 0x3b, 0x1e,
+ 0x15, 0xca, 0x5d, 0x26, 0xb3, 0x0a, 0x35, 0xf4, 0xbb, 0xad,
+ 0x71, 0xcb, 0x03, 0x1a, 0xcb, 0xfb, 0x83, 0xf0, 0xa8, 0xde,
+ 0xed, 0x5e, 0x3d, 0x98, 0xd2, 0xb0, 0xef, 0xad, 0xdf, 0x32,
+ 0xa0, 0x16, 0x7d, 0x0e, 0x29, 0xd8, 0x85, 0xca, 0x12, 0x97,
+ 0x56, 0xab, 0x6a, 0x26, 0xa4, 0x46, 0x3d, 0x87, 0xd7, 0xe0,
+ 0xb4, 0x3e, 0x28, 0x75, 0xac, 0x59, 0xc5, 0x71, 0x3a, 0x24,
+ 0x15, 0x76, 0x98, 0x72, 0x94, 0x2d, 0xd0, 0x0e, 0xbc, 0x9a,
+ 0x77, 0xd4, 0xe2, 0xb2, 0x76, 0x54, 0x4a, 0x56, 0xbe, 0x0b,
+ 0x43, 0xf8, 0x21, 0x6f, 0x54, 0x32, 0xde, 0xb7, 0xd5, 0xb7,
+ 0x08, 0x00, 0xd2, 0x57, 0x8c, 0x0b, 0x8b, 0x02, 0x3e, 0xdb,
+ 0x72, 0x54, 0x3a, 0xc0, 0x50, 0x66, 0xbc, 0xc9, 0x67, 0xf5,
+ 0x22, 0x28, 0xf2, 0x3c, 0x51, 0x94, 0x61, 0x26, 0x9a, 0xc6,
+ 0x42, 0x0e, 0x8b, 0x42, 0xad, 0x79, 0x40, 0xa9, 0x0b, 0xdc,
+ 0x84, 0xd5, 0x71, 0x83, 0x94, 0xd9, 0x83, 0x2f, 0x08, 0x74,
+ 0xbc, 0x37, 0x6a, 0x3e, 0x1e, 0xbc, 0xcc, 0x09, 0x23, 0x30,
+ 0x79, 0x01, 0x39, 0xf6, 0xe3, 0xa8, 0xc0, 0xfa, 0x7e, 0xdb,
+ 0x0b, 0x71, 0x3e, 0x4f, 0x1f, 0x69, 0x84, 0xa6, 0x58, 0x6c,
+ 0x36, 0x2c, 0xcc, 0xb4, 0x7c, 0x94, 0xec, 0x06, 0x0b, 0x11,
+ 0x53, 0x95, 0xe6, 0x05, 0x43, 0xa4, 0xe4, 0xea, 0x1d, 0x4f,
+ 0xdc, 0xd0, 0x38, 0x0e, 0x32, 0xa1, 0xde, 0xd9, 0x8d, 0xd8,
+ 0x20, 0xac, 0x04, 0x83, 0xf8, 0x1b, 0x55, 0x52, 0x16, 0x20,
+ 0xe3, 0x2e, 0x6d, 0x11, 0x15, 0x29, 0x2f, 0x3a, 0x7c, 0x80,
+ 0x0a, 0x71, 0x3d, 0x31, 0x9c, 0x1b, 0x73, 0x59, 0xe1, 0x0d,
+ 0x27, 0xc5, 0xc0, 0x6a, 0x72, 0x3a, 0x5b, 0xd6, 0xf6, 0x50,
+ 0xe6, 0x69, 0x48, 0x1e, 0xfd, 0xeb, 0x4a, 0x47, 0x73, 0xfb,
+ 0x88, 0x14, 0xea, 0x6d, 0x36, 0xe1, 0x4c, 0x2c, 0xf9, 0x04,
+ 0xc1, 0xb7, 0x29, 0xfc, 0x5d, 0x02, 0x5d, 0x1c, 0x4d, 0x31,
+ 0x4a, 0x51, 0x3f, 0xa4, 0x45, 0x19, 0x29, 0xc4, 0x32, 0xa6,
+ 0x45, 0xdb, 0x94, 0x3a, 0xbd, 0x76, 0x2c, 0xd6, 0x1a, 0xb1,
+ 0xff, 0xe7, 0x62, 0x75, 0x16, 0xe5, 0x0b, 0xa3, 0x3a, 0x93,
+ 0x84, 0xd6, 0xad, 0xc2, 0x24, 0x68, 0x3d, 0xd6, 0x07, 0xe4,
+ 0xbe, 0x5a, 0x49, 0x31, 0x06, 0xad, 0x3f, 0x31, 0x4a, 0x1c,
+ 0xf7, 0x58, 0xdf, 0x34, 0xcb, 0xc8, 0xa9, 0x07, 0x24, 0x42,
+ 0x63, 0xa5, 0x8e, 0xdd, 0x37, 0x78, 0x92, 0x68, 0x3f, 0xd8,
+ 0x2f, 0xea, 0x8c, 0xf1, 0x8e, 0xd4, 0x8b, 0xa7, 0x3f, 0xa0,
+ 0xfa, 0xaf, 0xf0, 0x35,
+ };
static const uint8_t test_x[] = {
- 0x06, 0x2c, 0x96, 0xae, 0x0e, 0x9e, 0x9b,
- 0xbb, 0x41, 0x51, 0x7a, 0xa7, 0xc5, 0xfe };
+ 0x16, 0x5c, 0xa6, 0xe0, 0x9b, 0x87, 0xfa, 0x2d, 0xbc, 0x13,
+ 0x20, 0xcd, 0xac, 0x4e, 0xcc, 0x60, 0x1e, 0x48, 0xec, 0xbe,
+ 0x73, 0x0c, 0xa8, 0x6b, 0x6e, 0x2a, 0xee, 0xdd, 0xd8, 0xf3,
+ 0x2d, 0x5f, 0x75, 0xf3, 0x07, 0x94, 0x88, 0x3d, 0xb1, 0x38,
+ 0xcf, 0xae, 0x4a, 0xcc, 0xcb, 0x6a, 0x80, 0xbc, 0xeb, 0x3b,
+ 0xaa, 0x0b, 0x18, 0x74, 0x58, 0x7c, 0x3e, 0x74, 0xef, 0xb6,
+ 0xd3, 0x15, 0xee, 0x73, 0x29, 0x88, 0x7b, 0x65, 0x02, 0x39,
+ 0x33, 0xec, 0x22, 0x06, 0x8c, 0x5b, 0xd6, 0x2f, 0x4c, 0xf7,
+ 0xe0, 0x97, 0x6d, 0x2a, 0x90, 0x36, 0xfe, 0x1a, 0x44, 0x4d,
+ 0x9d, 0x41, 0x4b, 0xcb, 0xec, 0x25, 0xf4, 0xc3, 0xa5, 0x91,
+ 0xd0, 0x90, 0xc9, 0x34, 0x7b, 0xba, 0x27, 0x30, 0x5a, 0xa2,
+ 0x21, 0x58, 0xce, 0x88, 0x25, 0x39, 0xaf, 0xf1, 0x17, 0x02,
+ 0x12, 0xf8, 0x55, 0xdc, 0xd2, 0x08, 0x5b, 0xd3, 0xc7, 0x8e,
+ 0xcf, 0x29, 0x85, 0x85, 0xdb, 0x5c, 0x08, 0xc2, 0xd7, 0xb0,
+ 0x33, 0x0e, 0xe3, 0xb9, 0x2c, 0x1a, 0x1d, 0x4b, 0xe5, 0x76,
+ 0x8f, 0xd3, 0x14, 0xb6, 0x8c, 0xdc, 0x9a, 0xe8, 0x15, 0x60,
+ 0x60, 0x5e, 0xaa, 0xf9, 0xfa, 0xa6, 0xb2, 0x4f, 0xff, 0x46,
+ 0xc1, 0x5e, 0x93, 0x50, 0x90, 0x7e, 0x4c, 0x26, 0xd7, 0xbb,
+ 0x21, 0x05, 0x3d, 0x27, 0xc5, 0x9b, 0x0d, 0x46, 0x69, 0xe4,
+ 0x74, 0x87, 0x74, 0x55, 0xee, 0x5f, 0xe5, 0x72, 0x04, 0x46,
+ 0x1f, 0x2e, 0x55, 0xc7, 0xcc, 0x2b, 0x2b, 0x39, 0x6d, 0x90,
+ 0x60, 0x31, 0x37, 0x5b, 0x44, 0xde, 0xfd, 0xf2, 0xd1, 0xc6,
+ 0x9c, 0x12, 0x82, 0xcc, 0x7c, 0xb1, 0x0e, 0xa9, 0x95, 0x9d,
+ 0xe0, 0xa8, 0x3e, 0xc1, 0xa3, 0x4a, 0x6a, 0x37, 0x59, 0x17,
+ 0x93, 0x63, 0x1e, 0xbf, 0x04, 0xa3, 0xaa, 0xc0, 0x1d, 0xc4,
+ 0x6d, 0x7a, 0xdc, 0x69, 0x9c, 0xb0, 0x22, 0x56, 0xd9, 0x76,
+ 0x92, 0x2d, 0x1e, 0x62, 0xae, 0xfd, 0xd6, 0x9b, 0xfd, 0x08,
+ 0x2c, 0x95, 0xec, 0xe7, 0x02, 0x43, 0x62, 0x68, 0x1a, 0xaf,
+ 0x46, 0x59, 0xb7, 0xce, 0x8e, 0x42, 0x24, 0xae, 0xf7, 0x0e,
+ 0x9a, 0x3b, 0xf8, 0x77, 0xdf, 0x26, 0x85, 0x9f, 0x45, 0xad,
+ 0x8c, 0xa9, 0x54, 0x9c, 0x46, 0x44, 0xd5, 0x8a, 0xe9, 0xcc,
+ 0x34, 0x5e, 0xc5, 0xd1, 0x42, 0x6f, 0x44, 0xf3, 0x0f, 0x90,
+ 0x3a, 0x32, 0x1a, 0x9c, 0x2a, 0x63, 0xec, 0x21, 0xb4, 0xfc,
+ 0xfa, 0xa5, 0xcf, 0xe7, 0x9e, 0x43, 0xc7, 0x49, 0x56, 0xbc,
+ 0x50, 0xc5, 0x84, 0xf0, 0x42, 0xc8, 0x6a, 0xf1, 0x78, 0xe4,
+ 0xaa, 0x06, 0x37, 0xe1, 0x30, 0xf7, 0x65, 0x97, 0xca, 0xfd,
+ 0x35, 0xfa, 0xeb, 0x48, 0x6d, 0xaa, 0x45, 0x46, 0x9d, 0xbc,
+ 0x1d, 0x98, 0x17, 0x45, 0xa3, 0xee, 0x21, 0xa0, 0x97, 0x38,
+ 0x80, 0xc5, 0x28, 0x1f,
+ };
static const uint8_t test_y[] = { /* y=g^x mod p */
- 0x1e, 0xca, 0x23, 0x2a, 0xfd, 0x34, 0xe1,
- 0x10, 0x7a, 0xff, 0xaf, 0x2d, 0xaa, 0x53 };
+ 0x93, 0xeb, 0x5c, 0x37, 0x1d, 0x3c, 0x06, 0x6f, 0xbf, 0xbe,
+ 0x96, 0x51, 0x26, 0x58, 0x81, 0x36, 0xc6, 0x4f, 0x9a, 0x34,
+ 0xc4, 0xc5, 0xa8, 0xa3, 0x2c, 0x41, 0x76, 0xa8, 0xc6, 0xc0,
+ 0xa0, 0xc8, 0x51, 0x36, 0xc4, 0x40, 0x4e, 0x2c, 0x69, 0xf7,
+ 0x51, 0xbb, 0xb0, 0xd6, 0xf5, 0xdb, 0x40, 0x29, 0x50, 0x3b,
+ 0x8a, 0xf9, 0xf3, 0x53, 0x78, 0xfc, 0x86, 0xe9, 0xf1, 0xe9,
+ 0xac, 0x85, 0x13, 0x65, 0x62, 0x22, 0x04, 0x1b, 0x14, 0x2a,
+ 0xf4, 0x8f, 0x2f, 0xf1, 0x2f, 0x81, 0xd6, 0x18, 0x0e, 0x76,
+ 0x91, 0x43, 0xb2, 0xfc, 0x7c, 0x6f, 0x0c, 0x45, 0x37, 0x31,
+ 0x31, 0x58, 0x5c, 0xdf, 0x42, 0x24, 0x7a, 0xba, 0x8b, 0x7f,
+ 0x79, 0x06, 0x07, 0xef, 0xd6, 0x06, 0xeb, 0xcb, 0x3c, 0xbd,
+ 0xbc, 0xe5, 0xff, 0xfd, 0x62, 0x15, 0x0c, 0x40, 0x46, 0x37,
+ 0xef, 0xd0, 0xa1, 0xde, 0x63, 0x4f, 0x20, 0x0b, 0x45, 0x7d,
+ 0x06, 0x77, 0xfd, 0x23, 0xc1, 0x32, 0x8a, 0x89, 0x65, 0x16,
+ 0xe8, 0x48, 0x12, 0x1c, 0x25, 0x33, 0x2d, 0xbd, 0xd8, 0x9f,
+ 0x1c, 0x9d, 0xbc, 0xe3, 0x08, 0x60, 0x87, 0x1a, 0xc6, 0x06,
+ 0x36, 0xd2, 0xac, 0x09, 0x6d, 0x99, 0x02, 0x89, 0xc6, 0x12,
+ 0x93, 0x8c, 0x4b, 0xd0, 0x7e, 0x36, 0x8a, 0xd6, 0xa0, 0x97,
+ 0x4f, 0x97, 0x3f, 0x97, 0x0b, 0xfe, 0x05, 0xfc, 0xc8, 0xef,
+ 0x21, 0x4d, 0x4a, 0x06, 0x6e, 0xb4, 0xa6, 0x4f, 0xe1, 0xdd,
+ 0x44, 0x06, 0xfa, 0xd5, 0x0e, 0x54, 0xf5, 0x54, 0x3e, 0x8c,
+ 0xb9, 0x85, 0x86, 0x00, 0x40, 0x98, 0xe7, 0x01, 0xdd, 0x93,
+ 0x9d, 0x95, 0xea, 0xf0, 0xd3, 0x99, 0x4b, 0xeb, 0xd5, 0x79,
+ 0x47, 0xa4, 0xad, 0x2a, 0xe0, 0x4d, 0x36, 0x3b, 0x46, 0x10,
+ 0x96, 0xbb, 0x48, 0xe9, 0xa1, 0x78, 0x01, 0x35, 0x0a, 0x5c,
+ 0x7b, 0x3f, 0xf5, 0xf7, 0xb1, 0xe3, 0x97, 0x17, 0x4d, 0x76,
+ 0x10, 0x8d, 0x68, 0x4c, 0x94, 0x7d, 0xee, 0x0e, 0x20, 0x8b,
+ 0xce, 0x7d, 0x0a, 0xa3, 0x51, 0xfb, 0xe6, 0xcf, 0xf0, 0x0e,
+ 0x7f, 0x3c, 0xd4, 0xef, 0x56, 0x31, 0xb2, 0x95, 0xf0, 0x5f,
+ 0x4b, 0x9c, 0x03, 0x9e, 0xae, 0xb1, 0xc1, 0x46, 0xd7, 0xc0,
+ 0x4f, 0xb0, 0xf6, 0x6c, 0xe1, 0xe9, 0x2a, 0x97, 0xe0, 0x3f,
+ 0x3a, 0x93, 0x04, 0xcd, 0x41, 0x7d, 0x45, 0x03, 0xb3, 0x40,
+ 0x20, 0xe6, 0xad, 0x2d, 0xd3, 0xf7, 0x32, 0x7b, 0xcc, 0x4f,
+ 0x81, 0x18, 0x4c, 0x50, 0x77, 0xc4, 0xb7, 0x6a, 0x4d, 0x05,
+ 0xd8, 0x6d, 0xbf, 0x6f, 0xba, 0x1d, 0x38, 0x78, 0x87, 0xd2,
+ 0x8e, 0xc2, 0x6d, 0xb6, 0xed, 0x66, 0x61, 0xa8, 0xb9, 0x19,
+ 0x0e, 0x93, 0xd1, 0xcd, 0x5b, 0xbe, 0x19, 0x05, 0x52, 0x43,
+ 0xd6, 0xc1, 0x07, 0x3c, 0x6a, 0x62, 0xbd, 0x33, 0x9b, 0x1b,
+ 0x02, 0x42, 0x61, 0x14,
+ };
gnutls_pk_params_init(&priv);
gnutls_pk_params_init(&pub);
priv.algo = pub.algo = GNUTLS_PK_DH;
- ret = _gnutls_mpi_init_scan(&priv.params[DH_P], test_p, sizeof(test_p));
+ ret = _gnutls_mpi_init_scan(&priv.params[DH_P],
+ gnutls_ffdhe_3072_group_prime.data,
+ gnutls_ffdhe_3072_group_prime.size);
if (ret < 0) {
gnutls_assert();
goto cleanup;
}
- ret = _gnutls_mpi_init_scan(&priv.params[DH_G], test_g, sizeof(test_g));
+ ret = _gnutls_mpi_init_scan(&priv.params[DH_G],
+ gnutls_ffdhe_3072_group_generator.data,
+ gnutls_ffdhe_3072_group_generator.size);
if (ret < 0) {
gnutls_assert();
goto cleanup;
diff --git a/lib/dh-primes.c b/lib/dh-primes.c
index a440b5b98..94b69e345 100644
--- a/lib/dh-primes.c
+++ b/lib/dh-primes.c
@@ -23,8 +23,6 @@
#include "gnutls_int.h"
#include <gnutls/gnutls.h>
-#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
-
#include "dh.h"
static const unsigned char ffdhe_generator = 0x02;
@@ -1934,5 +1932,3 @@ _gnutls_dh_prime_match_fips_approved(const uint8_t *prime,
return 0;
}
-
-#endif
--
2.26.2

View File

@ -1,713 +0,0 @@
From 93c0e3ba4d2cfee86b32f28f33303a2193c4133c Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Mon, 5 Oct 2020 16:12:46 +0200
Subject: [PATCH 1/4] fips: add self-tests for HKDF
FIPS140-2 IG D.8 mandates self-test on approved KDF algorithms. As
the guidance only requires running a single instance of each KDF
mechanism, this only exercises HKDF-Extract and HKDF-Expand operations
with HMAC-SHA-256 as the underlying MAC.
Although HKDF is non-approved, it would be sensible to do that as it
will be approved in FIPS140-3.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
devel/libgnutls-latest-x86_64.abi | 1 +
lib/crypto-selftests.c | 159 ++++++++++++++++++++++++++++++
lib/fips.c | 7 ++
lib/includes/gnutls/self-test.h | 1 +
lib/libgnutls.map | 1 +
5 files changed, 169 insertions(+)
diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c
index 7a1c7729c..bd148b6af 100644
--- a/lib/crypto-selftests.c
+++ b/lib/crypto-selftests.c
@@ -2917,3 +2917,162 @@ int gnutls_digest_self_test(unsigned flags, gnutls_digest_algorithm_t digest)
return 0;
}
+
+struct hkdf_vectors_st {
+ const uint8_t *ikm;
+ unsigned int ikm_size;
+ const uint8_t *salt;
+ unsigned int salt_size;
+ const uint8_t *prk;
+ unsigned int prk_size;
+ const uint8_t *info;
+ unsigned int info_size;
+ const uint8_t *okm;
+ unsigned int okm_size;
+};
+
+const struct hkdf_vectors_st hkdf_sha256_vectors[] = {
+ /* RFC 5869: A.1. Test Case 1: Basic test case with SHA-256 */
+ {
+ STR(ikm, ikm_size,
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"),
+ STR(salt, salt_size,
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c"),
+ STR(prk, prk_size,
+ "\x07\x77\x09\x36\x2c\x2e\x32\xdf\x0d\xdc\x3f\x0d\xc4\x7b"
+ "\xba\x63\x90\xb6\xc7\x3b\xb5\x0f\x9c\x31\x22\xec\x84\x4a"
+ "\xd7\xc2\xb3\xe5"),
+ STR(info, info_size,
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9"),
+ STR(okm, okm_size,
+ "\x3c\xb2\x5f\x25\xfa\xac\xd5\x7a\x90\x43\x4f\x64\xd0\x36"
+ "\x2f\x2a\x2d\x2d\x0a\x90\xcf\x1a\x5a\x4c\x5d\xb0\x2d\x56"
+ "\xec\xc4\xc5\xbf\x34\x00\x72\x08\xd5\xb8\x87\x18\x58\x65"),
+ },
+ /* RFC 5869: A.2. Test Case 2: Test with SHA-256 and longer inputs/outputs */
+ {
+ STR(ikm, ikm_size,
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d"
+ "\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b"
+ "\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29"
+ "\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37"
+ "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45"
+ "\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"),
+ STR(salt, salt_size,
+ "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d"
+ "\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b"
+ "\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89"
+ "\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5"
+ "\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"),
+ STR(prk, prk_size,
+ "\x06\xa6\xb8\x8c\x58\x53\x36\x1a\x06\x10\x4c\x9c\xeb\x35"
+ "\xb4\x5c\xef\x76\x00\x14\x90\x46\x71\x01\x4a\x19\x3f\x40"
+ "\xc1\x5f\xc2\x44"),
+ STR(info, info_size,
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd"
+ "\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb"
+ "\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9"
+ "\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+ "\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5"
+ "\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"),
+ STR(okm, okm_size,
+ "\xb1\x1e\x39\x8d\xc8\x03\x27\xa1\xc8\xe7\xf7\x8c\x59\x6a"
+ "\x49\x34\x4f\x01\x2e\xda\x2d\x4e\xfa\xd8\xa0\x50\xcc\x4c"
+ "\x19\xaf\xa9\x7c\x59\x04\x5a\x99\xca\xc7\x82\x72\x71\xcb"
+ "\x41\xc6\x5e\x59\x0e\x09\xda\x32\x75\x60\x0c\x2f\x09\xb8"
+ "\x36\x77\x93\xa9\xac\xa3\xdb\x71\xcc\x30\xc5\x81\x79\xec"
+ "\x3e\x87\xc1\x4c\x01\xd5\xc1\xf3\x43\x4f\x1d\x87"),
+ },
+};
+
+static int test_hkdf(gnutls_mac_algorithm_t mac,
+ const struct hkdf_vectors_st *vectors,
+ size_t vectors_size, unsigned flags)
+{
+ unsigned int i;
+
+ for (i = 0; i < vectors_size; i++) {
+ gnutls_datum_t ikm, prk, salt, info;
+ uint8_t output[4096];
+ int ret;
+
+ ikm.data = (void *) vectors[i].ikm;
+ ikm.size = vectors[i].ikm_size;
+ salt.data = (void *) vectors[i].salt;
+ salt.size = vectors[i].salt_size;
+
+ ret = gnutls_hkdf_extract(mac, &ikm, &salt, output);
+ if (ret < 0) {
+ _gnutls_debug_log("error extracting HKDF: MAC-%s\n",
+ gnutls_mac_get_name(mac));
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+
+ if (memcmp(output, vectors[i].prk, vectors[i].prk_size) != 0) {
+ _gnutls_debug_log
+ ("HKDF extract: MAC-%s test vector failed!\n",
+ gnutls_mac_get_name(mac));
+
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+
+ prk.data = (void *) vectors[i].prk;
+ prk.size = vectors[i].prk_size;
+ info.data = (void *) vectors[i].info;
+ info.size = vectors[i].info_size;
+
+ ret = gnutls_hkdf_expand(mac, &prk, &info,
+ output, vectors[i].okm_size);
+ if (ret < 0) {
+ _gnutls_debug_log("error extracting HKDF: MAC-%s\n",
+ gnutls_mac_get_name(mac));
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+
+ if (memcmp(output, vectors[i].okm, vectors[i].okm_size) != 0) {
+ _gnutls_debug_log
+ ("HKDF expand: MAC-%s test vector failed!\n",
+ gnutls_mac_get_name(mac));
+
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+ }
+
+ _gnutls_debug_log
+ ("HKDF: MAC-%s self check succeeded\n",
+ gnutls_mac_get_name(mac));
+
+ return 0;
+}
+
+/*-
+ * gnutls_hkdf_self_test:
+ * @flags: GNUTLS_SELF_TEST_FLAG flags
+ * @mac: the message authentication algorithm to use
+ *
+ * This function will run self tests on HKDF with the provided mac.
+ *
+ * Returns: Zero or a negative error code on error.
+ *
+ * Since: 3.3.0-FIPS140
+ -*/
+int gnutls_hkdf_self_test(unsigned flags, gnutls_mac_algorithm_t mac)
+{
+ int ret;
+
+ if (flags & GNUTLS_SELF_TEST_FLAG_ALL)
+ mac = GNUTLS_MAC_UNKNOWN;
+
+ switch (mac) {
+ case GNUTLS_MAC_UNKNOWN:
+ CASE(GNUTLS_MAC_SHA256, test_hkdf, hkdf_sha256_vectors);
+
+ break;
+ default:
+ return gnutls_assert_val(GNUTLS_E_NO_SELF_TEST);
+ }
+
+ return 0;
+}
diff --git a/lib/fips.c b/lib/fips.c
index f8b10f750..48891ed57 100644
--- a/lib/fips.c
+++ b/lib/fips.c
@@ -423,6 +423,13 @@ int _gnutls_fips_perform_self_checks2(void)
goto error;
}
+ /* HKDF */
+ ret = gnutls_hkdf_self_test(0, GNUTLS_MAC_SHA256);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
if (_gnutls_rnd_ops.self_test == NULL) {
gnutls_assert();
goto error;
diff --git a/lib/includes/gnutls/self-test.h b/lib/includes/gnutls/self-test.h
index aacbe94ca..9b7be8159 100644
--- a/lib/includes/gnutls/self-test.h
+++ b/lib/includes/gnutls/self-test.h
@@ -34,5 +34,6 @@ int gnutls_cipher_self_test(unsigned flags, gnutls_cipher_algorithm_t cipher);
int gnutls_mac_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
int gnutls_digest_self_test(unsigned flags, gnutls_digest_algorithm_t digest);
int gnutls_pk_self_test(unsigned flags, gnutls_pk_algorithm_t pk);
+int gnutls_hkdf_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
#endif
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 61276e534..386b66f83 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1347,6 +1347,7 @@ GNUTLS_FIPS140_3_4 {
gnutls_pk_self_test;
gnutls_mac_self_test;
gnutls_digest_self_test;
+ gnutls_hkdf_self_test;
#for FIPS140-2 validation
drbg_aes_reseed;
drbg_aes_init;
--
2.26.2
From 31cc94275cd267f4e0db60999cc932fd76d43d5a Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Mon, 5 Oct 2020 16:59:50 +0200
Subject: [PATCH 2/4] fips: add self-tests for PBKDF2
FIPS140-2 IG D.8 mandates self-tests on approved KDF algorithms. As
the guidance only requires running a single instance of each KDF
mechanism, this only exercises PBKDF2 with HMAC-SHA-256 as the
underlying MAC algorithm.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
devel/libgnutls-latest-x86_64.abi | 1 +
lib/crypto-selftests.c | 107 ++++++++++++++++++++++++++++++
lib/fips.c | 7 ++
lib/includes/gnutls/self-test.h | 1 +
lib/libgnutls.map | 1 +
5 files changed, 117 insertions(+)
diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c
index bd148b6af..c4b0bd207 100644
--- a/lib/crypto-selftests.c
+++ b/lib/crypto-selftests.c
@@ -3076,3 +3076,110 @@ int gnutls_hkdf_self_test(unsigned flags, gnutls_mac_algorithm_t mac)
return 0;
}
+
+struct pbkdf2_vectors_st {
+ const uint8_t *key;
+ size_t key_size;
+ const uint8_t *salt;
+ size_t salt_size;
+ unsigned iter_count;
+ const uint8_t *output;
+ size_t output_size;
+};
+
+const struct pbkdf2_vectors_st pbkdf2_sha256_vectors[] = {
+ /* RFC 7914: 11. Test Vectors for PBKDF2 with HMAC-SHA-256 */
+ {
+ STR(key, key_size, "passwd"),
+ STR(salt, salt_size, "salt"),
+ .iter_count = 1,
+ STR(output, output_size,
+ "\x55\xac\x04\x6e\x56\xe3\x08\x9f\xec\x16\x91\xc2\x25\x44"
+ "\xb6\x05\xf9\x41\x85\x21\x6d\xde\x04\x65\xe6\x8b\x9d\x57"
+ "\xc2\x0d\xac\xbc\x49\xca\x9c\xcc\xf1\x79\xb6\x45\x99\x16"
+ "\x64\xb3\x9d\x77\xef\x31\x7c\x71\xb8\x45\xb1\xe3\x0b\xd5"
+ "\x09\x11\x20\x41\xd3\xa1\x97\x83"),
+ },
+ /* RFC 7914: 11. Test Vectors for PBKDF2 with HMAC-SHA-256 */
+ {
+ STR(key, key_size, "Password"),
+ STR(salt, salt_size, "NaCl"),
+ .iter_count = 80000,
+ STR(output, output_size,
+ "\x4d\xdc\xd8\xf6\x0b\x98\xbe\x21\x83\x0c\xee\x5e\xf2\x27"
+ "\x01\xf9\x64\x1a\x44\x18\xd0\x4c\x04\x14\xae\xff\x08\x87"
+ "\x6b\x34\xab\x56\xa1\xd4\x25\xa1\x22\x58\x33\x54\x9a\xdb"
+ "\x84\x1b\x51\xc9\xb3\x17\x6a\x27\x2b\xde\xbb\xa1\xd0\x78"
+ "\x47\x8f\x62\xb3\x97\xf3\x3c\x8d"),
+ },
+};
+
+static int test_pbkdf2(gnutls_mac_algorithm_t mac,
+ const struct pbkdf2_vectors_st *vectors,
+ size_t vectors_size, unsigned flags)
+{
+ unsigned int i;
+
+ for (i = 0; i < vectors_size; i++) {
+ gnutls_datum_t key, salt;
+ uint8_t output[4096];
+ int ret;
+
+ key.data = (void *) vectors[i].key;
+ key.size = vectors[i].key_size;
+ salt.data = (void *) vectors[i].salt;
+ salt.size = vectors[i].salt_size;
+
+ ret = gnutls_pbkdf2(mac, &key, &salt, vectors[i].iter_count,
+ output, vectors[i].output_size);
+ if (ret < 0) {
+ _gnutls_debug_log("error calculating PBKDF2: MAC-%s\n",
+ gnutls_mac_get_name(mac));
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+
+ if (memcmp(output, vectors[i].output, vectors[i].output_size) != 0) {
+ _gnutls_debug_log
+ ("PBKDF2: MAC-%s test vector failed!\n",
+ gnutls_mac_get_name(mac));
+
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+ }
+
+ _gnutls_debug_log
+ ("PBKDF2: MAC-%s self check succeeded\n",
+ gnutls_mac_get_name(mac));
+
+ return 0;
+}
+
+/*-
+ * gnutls_pbkdf2_self_test:
+ * @flags: GNUTLS_SELF_TEST_FLAG flags
+ * @mac: the message authentication algorithm to use
+ *
+ * This function will run self tests on PBKDF2 with the provided mac.
+ *
+ * Returns: Zero or a negative error code on error.
+ *
+ * Since: 3.3.0-FIPS140
+ -*/
+int gnutls_pbkdf2_self_test(unsigned flags, gnutls_mac_algorithm_t mac)
+{
+ int ret;
+
+ if (flags & GNUTLS_SELF_TEST_FLAG_ALL)
+ mac = GNUTLS_MAC_UNKNOWN;
+
+ switch (mac) {
+ case GNUTLS_MAC_UNKNOWN:
+ CASE(GNUTLS_MAC_SHA256, test_pbkdf2, pbkdf2_sha256_vectors);
+
+ break;
+ default:
+ return gnutls_assert_val(GNUTLS_E_NO_SELF_TEST);
+ }
+
+ return 0;
+}
diff --git a/lib/fips.c b/lib/fips.c
index 48891ed57..7cfab1049 100644
--- a/lib/fips.c
+++ b/lib/fips.c
@@ -430,6 +430,13 @@ int _gnutls_fips_perform_self_checks2(void)
goto error;
}
+ /* PBKDF2 */
+ ret = gnutls_pbkdf2_self_test(0, GNUTLS_MAC_SHA256);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
if (_gnutls_rnd_ops.self_test == NULL) {
gnutls_assert();
goto error;
diff --git a/lib/includes/gnutls/self-test.h b/lib/includes/gnutls/self-test.h
index 9b7be8159..958c0da8f 100644
--- a/lib/includes/gnutls/self-test.h
+++ b/lib/includes/gnutls/self-test.h
@@ -35,5 +35,6 @@ int gnutls_mac_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
int gnutls_digest_self_test(unsigned flags, gnutls_digest_algorithm_t digest);
int gnutls_pk_self_test(unsigned flags, gnutls_pk_algorithm_t pk);
int gnutls_hkdf_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
+int gnutls_pbkdf2_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
#endif
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 386b66f83..f5537a386 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1348,6 +1348,7 @@ GNUTLS_FIPS140_3_4 {
gnutls_mac_self_test;
gnutls_digest_self_test;
gnutls_hkdf_self_test;
+ gnutls_pbkdf2_self_test;
#for FIPS140-2 validation
drbg_aes_reseed;
drbg_aes_init;
--
2.26.2
From d1a3235e8c829855969d00364d8b5456fce2c78c Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Mon, 5 Oct 2020 17:44:30 +0200
Subject: [PATCH 3/4] fips: add self-tests for TLS-PRF
FIPS140-2 IG D.8 mandates self-tests on approved KDF algorithms. As
the guidance only requires to run a single instance of each KDF
mechanism, this only exercises TLS1.2 PRF with HMAC-SHA-256 as the
underlying MAC algorithm.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
devel/libgnutls-latest-x86_64.abi | 1 +
lib/crypto-selftests.c | 196 ++++++++++++++++++++++++++++++
lib/fips.c | 7 ++
lib/includes/gnutls/self-test.h | 1 +
lib/libgnutls.map | 1 +
5 files changed, 206 insertions(+)
diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c
index c4b0bd207..b740936d6 100644
--- a/lib/crypto-selftests.c
+++ b/lib/crypto-selftests.c
@@ -3183,3 +3183,199 @@ int gnutls_pbkdf2_self_test(unsigned flags, gnutls_mac_algorithm_t mac)
return 0;
}
+
+struct tlsprf_vectors_st {
+ const uint8_t *key;
+ size_t key_size;
+ const uint8_t *label;
+ size_t label_size;
+ const uint8_t *seed;
+ size_t seed_size;
+ const uint8_t *output;
+ size_t output_size;
+};
+
+const struct tlsprf_vectors_st tls10prf_vectors[] = {
+ /* tests/tls10-prf.c: test1 */
+ {
+ STR(key, key_size,
+ "\x26\x3b\xdb\xbb\x6f\x6d\x4c\x66\x4e\x05\x8d\x0a\xa9\xd3"
+ "\x21\xbe"),
+ STR(label, label_size,
+ "test label"),
+ STR(seed, seed_size,
+ "\xb9\x20\x57\x3b\x19\x96\x01\x02\x4f\x04\xd6\xdc\x61\x96"
+ "\x6e\x65"),
+ STR(output, output_size,
+ "\x66\x17\x99\x37\x65\xfa\x6c\xa7\x03\xd1\x9e\xc7\x0d\xd5"
+ "\xdd\x16\x0f\xfc\xc0\x77\x25\xfa\xfb\x71\x4a\x9f\x81\x5a"
+ "\x2a\x30\xbf\xb7\xe3\xbb\xfb\x7e\xee\x57\x4b\x3b\x61\x3e"
+ "\xb7\xfe\x80\xee\xc9\x69\x1d\x8c\x1b\x0e\x2d\x9b\x3c\x8b"
+ "\x4b\x02\xb6\xb6\xd6\xdb\x88\xe2\x09\x46\x23\xef\x62\x40"
+ "\x60\x7e\xda\x7a\xbe\x3c\x84\x6e\x82\xa3"),
+ },
+};
+
+const struct tlsprf_vectors_st tls12prf_sha256_vectors[] = {
+ /* tests/tls12-prf.c: sha256_test1 */
+ {
+ STR(key, key_size,
+ "\x04\x50\xb0\xea\x9e\xcd\x36\x02\xee\x0d\x76\xc5\xc3\xc8"
+ "\x6f\x4a"),
+ STR(label, label_size,
+ "test label"),
+ STR(seed, seed_size,
+ "\x20\x7a\xcc\x02\x54\xb8\x67\xf5\xb9\x25\xb4\x5a\x33\x60"
+ "\x1d\x8b"),
+ STR(output, output_size,
+ "\xae\x67\x9e\x0e\x71\x4f\x59\x75\x76\x37\x68\xb1\x66\x97"
+ "\x9e\x1d"),
+ },
+ /* tests/tls12-prf.c: sha256_test2 */
+ {
+ STR(key, key_size,
+ "\x34\x20\x4a\x9d\xf0\xbe\x6e\xb4\xe9\x25\xa8\x02\x7c\xf6"
+ "\xc6\x02"),
+ STR(label, label_size,
+ "test label"),
+ STR(seed, seed_size,
+ "\x98\xb2\xc4\x0b\xcd\x66\x4c\x83\xbb\x92\x0c\x18\x20\x1a"
+ "\x63\x95"),
+ STR(output, output_size,
+ "\xaf\xa9\x31\x24\x53\xc2\x2f\xa8\x3d\x2b\x51\x1b\x37\x2d"
+ "\x73\xa4\x02\xa2\xa6\x28\x73\x23\x9a\x51\xfa\xde\x45\x08"
+ "\x2f\xaf\x3f\xd2\xbb\x7f\xfb\x3e\x9b\xf3\x6e\x28\xb3\x14"
+ "\x1a\xab\xa4\x84\x00\x53\x32\xa9\xf9\xe3\x88\xa4\xd3\x29"
+ "\xf1\x58\x7a\x4b\x31\x7d\xa0\x77\x08\xea\x1b\xa9\x5a\x53"
+ "\xf8\x78\x67\x24\xbd\x83\xce\x4b\x03\xaf"),
+ },
+ /* tests/tls12-prf.c: sha256_test3 */
+ {
+ STR(key, key_size,
+ "\xa3\x69\x1a\xa1\xf6\x81\x4b\x80\x59\x2b\xf1\xcf\x2a\xcf"
+ "\x16\x97"),
+ STR(label, label_size,
+ "test label"),
+ STR(seed, seed_size,
+ "\x55\x23\xd4\x1e\x32\x0e\x69\x4d\x0c\x1f\xf5\x73\x4d\x83"
+ "\x0b\x93\x3e\x46\x92\x70\x71\xc9\x26\x21"),
+ STR(output, output_size,
+ "\x6a\xd0\x98\x4f\xa0\x6f\x78\xfe\x16\x1b\xd4\x6d\x7c\x26"
+ "\x1d\xe4\x33\x40\xd7\x28\xdd\xdc\x3d\x0f\xf0\xdd\x7e\x0d"),
+ },
+ /* tests/tls12-prf.c: sha256_test4 */
+ {
+ STR(key, key_size,
+ "\x21\x0e\xc9\x37\x06\x97\x07\xe5\x46\x5b\xc4\x6b\xf7\x79"
+ "\xe1\x04\x10\x8b\x18\xfd\xb7\x93\xbe\x7b\x21\x8d\xbf\x14"
+ "\x5c\x86\x41\xf3"),
+ STR(label, label_size,
+ "test label"),
+ STR(seed, seed_size,
+ "\x1e\x35\x1a\x0b\xaf\x35\xc7\x99\x45\x92\x43\x94\xb8\x81"
+ "\xcf\xe3\x1d\xae\x8f\x1c\x1e\xd5\x4d\x3b"),
+ STR(output, output_size,
+ "\x76\x53\xfa\x80\x9c\xde\x3b\x55\x3c\x4a\x17\xe2\xcd\xbc"
+ "\xc9\x18\xf3\x65\x27\xf2\x22\x19\xa7\xd7\xf9\x5d\x97\x24"
+ "\x3f\xf2\xd5\xde\xe8\x26\x5e\xf0\xaf\x03"),
+ },
+};
+
+const struct tlsprf_vectors_st tls12prf_sha384_vectors[] = {
+ /* tests/tls12-prf.c: sha384_test1
+ * https://www.ietf.org/mail-archive/web/tls/current/msg03416.html
+ */
+ {
+ STR(key, key_size,
+ "\xb8\x0b\x73\x3d\x6c\xee\xfc\xdc\x71\x56\x6e\xa4\x8e\x55"
+ "\x67\xdf"),
+ STR(label, label_size,
+ "test label"),
+ STR(seed, seed_size,
+ "\xcd\x66\x5c\xf6\xa8\x44\x7d\xd6\xff\x8b\x27\x55\x5e\xdb"
+ "\x74\x65"),
+ STR(output, output_size,
+ "\x7b\x0c\x18\xe9\xce\xd4\x10\xed\x18\x04\xf2\xcf\xa3\x4a"
+ "\x33\x6a\x1c\x14\xdf\xfb\x49\x00\xbb\x5f\xd7\x94\x21\x07"
+ "\xe8\x1c\x83\xcd\xe9\xca\x0f\xaa\x60\xbe\x9f\xe3\x4f\x82"
+ "\xb1\x23\x3c\x91\x46\xa0\xe5\x34\xcb\x40\x0f\xed\x27\x00"
+ "\x88\x4f\x9d\xc2\x36\xf8\x0e\xdd\x8b\xfa\x96\x11\x44\xc9"
+ "\xe8\xd7\x92\xec\xa7\x22\xa7\xb3\x2f\xc3\xd4\x16\xd4\x73"
+ "\xeb\xc2\xc5\xfd\x4a\xbf\xda\xd0\x5d\x91\x84\x25\x9b\x5b"
+ "\xf8\xcd\x4d\x90\xfa\x0d\x31\xe2\xde\xc4\x79\xe4\xf1\xa2"
+ "\x60\x66\xf2\xee\xa9\xa6\x92\x36\xa3\xe5\x26\x55\xc9\xe9"
+ "\xae\xe6\x91\xc8\xf3\xa2\x68\x54\x30\x8d\x5e\xaa\x3b\xe8"
+ "\x5e\x09\x90\x70\x3d\x73\xe5\x6f"),
+ },
+};
+
+static int test_tlsprf(gnutls_mac_algorithm_t mac,
+ const struct tlsprf_vectors_st *vectors,
+ size_t vectors_size, unsigned flags)
+{
+ unsigned int i;
+
+ for (i = 0; i < vectors_size; i++) {
+ char output[4096];
+ int ret;
+
+ ret = _gnutls_prf_raw(mac,
+ vectors[i].key_size, vectors[i].key,
+ vectors[i].label_size, (const char *)vectors[i].label,
+ vectors[i].seed_size, vectors[i].seed,
+ vectors[i].output_size, output);
+ if (ret < 0) {
+ _gnutls_debug_log("error calculating TLS-PRF: MAC-%s\n",
+ gnutls_mac_get_name(mac));
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+
+ if (memcmp(output, vectors[i].output, vectors[i].output_size) != 0) {
+ _gnutls_debug_log
+ ("TLS-PRF: MAC-%s test vector failed!\n",
+ gnutls_mac_get_name(mac));
+
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+ }
+
+ _gnutls_debug_log
+ ("TLS-PRF: MAC-%s self check succeeded\n",
+ gnutls_mac_get_name(mac));
+
+ return 0;
+}
+
+/*-
+ * gnutls_tlsprf_self_test:
+ * @flags: GNUTLS_SELF_TEST_FLAG flags
+ * @mac: the message authentication algorithm to use
+ *
+ * This function will run self tests on TLS-PRF with the provided mac.
+ *
+ * Returns: Zero or a negative error code on error.
+ *
+ * Since: 3.3.0-FIPS140
+ -*/
+int gnutls_tlsprf_self_test(unsigned flags, gnutls_mac_algorithm_t mac)
+{
+ int ret;
+
+ if (flags & GNUTLS_SELF_TEST_FLAG_ALL)
+ mac = GNUTLS_MAC_UNKNOWN;
+
+ switch (mac) {
+ case GNUTLS_MAC_UNKNOWN:
+ NON_FIPS_CASE(GNUTLS_MAC_MD5_SHA1, test_tlsprf, tls10prf_vectors);
+ FALLTHROUGH;
+ CASE(GNUTLS_MAC_SHA256, test_tlsprf, tls12prf_sha256_vectors);
+ FALLTHROUGH;
+ CASE(GNUTLS_MAC_SHA384, test_tlsprf, tls12prf_sha384_vectors);
+
+ break;
+ default:
+ return gnutls_assert_val(GNUTLS_E_NO_SELF_TEST);
+ }
+
+ return 0;
+}
diff --git a/lib/fips.c b/lib/fips.c
index 7cfab1049..30d396b2c 100644
--- a/lib/fips.c
+++ b/lib/fips.c
@@ -437,6 +437,13 @@ int _gnutls_fips_perform_self_checks2(void)
goto error;
}
+ /* TLS-PRF */
+ ret = gnutls_tlsprf_self_test(0, GNUTLS_MAC_SHA256);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
if (_gnutls_rnd_ops.self_test == NULL) {
gnutls_assert();
goto error;
diff --git a/lib/includes/gnutls/self-test.h b/lib/includes/gnutls/self-test.h
index 958c0da8f..88b5a8dbf 100644
--- a/lib/includes/gnutls/self-test.h
+++ b/lib/includes/gnutls/self-test.h
@@ -36,5 +36,6 @@ int gnutls_digest_self_test(unsigned flags, gnutls_digest_algorithm_t digest);
int gnutls_pk_self_test(unsigned flags, gnutls_pk_algorithm_t pk);
int gnutls_hkdf_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
int gnutls_pbkdf2_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
+int gnutls_tlsprf_self_test(unsigned flags, gnutls_mac_algorithm_t mac);
#endif
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index f5537a386..643d400a1 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1349,6 +1349,7 @@ GNUTLS_FIPS140_3_4 {
gnutls_digest_self_test;
gnutls_hkdf_self_test;
gnutls_pbkdf2_self_test;
+ gnutls_tlsprf_self_test;
#for FIPS140-2 validation
drbg_aes_reseed;
drbg_aes_init;
--
2.26.2
From af3df0102fc377591a6de3112b034d4a492fc92c Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Mon, 5 Oct 2020 17:59:46 +0200
Subject: [PATCH 4/4] fips: run CMAC self-tests
FIPS140-2 IG D.8 mandates self-tests on CMAC.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/fips.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/lib/fips.c b/lib/fips.c
index 30d396b2c..51567953d 100644
--- a/lib/fips.c
+++ b/lib/fips.c
@@ -398,6 +398,12 @@ int _gnutls_fips_perform_self_checks2(void)
goto error;
}
+ ret = gnutls_mac_self_test(0, GNUTLS_MAC_AES_CMAC_256);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
/* PK */
ret = gnutls_pk_self_test(0, GNUTLS_PK_RSA);
if (ret < 0) {
--
2.26.2

View File

@ -1,226 +0,0 @@
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

File diff suppressed because it is too large Load Diff

View File

@ -1,35 +0,0 @@
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

View File

@ -1,116 +0,0 @@
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

View File

@ -1,41 +0,0 @@
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

View File

@ -1,58 +0,0 @@
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

View File

@ -1,488 +0,0 @@
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

View File

@ -1,944 +0,0 @@
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

View File

@ -1,166 +0,0 @@
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

View File

@ -1,95 +0,0 @@
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

View File

@ -1,498 +0,0 @@
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

View File

@ -1,176 +0,0 @@
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

View File

@ -1,552 +0,0 @@
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

View File

@ -1,244 +0,0 @@
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

View File

@ -1,60 +0,0 @@
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

View File

@ -1,44 +0,0 @@
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

View File

@ -1,107 +0,0 @@
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

View File

@ -1,247 +0,0 @@
From 300c6315d2e644ae81b43fa2dd7bbf68b3afb5b2 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Thu, 18 Nov 2021 19:02:03 +0100
Subject: [PATCH 1/2] accelerated: fix CPU feature detection for Intel CPUs
This fixes read_cpuid_vals to correctly read the CPUID quadruple, as
well as to set the bit the ustream CRYPTOGAMS uses to identify Intel
CPUs.
Suggested by Rafael Gieschke in:
https://gitlab.com/gnutls/gnutls/-/issues/1282
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/accelerated/x86/x86-common.c | 91 +++++++++++++++++++++++++-------
1 file changed, 71 insertions(+), 20 deletions(-)
diff --git a/lib/accelerated/x86/x86-common.c b/lib/accelerated/x86/x86-common.c
index 3845c6b4c9..cf615ef24f 100644
--- a/lib/accelerated/x86/x86-common.c
+++ b/lib/accelerated/x86/x86-common.c
@@ -81,15 +81,38 @@ unsigned int _gnutls_x86_cpuid_s[4];
# define bit_AVX 0x10000000
#endif
-#ifndef OSXSAVE_MASK
-/* OSXSAVE|FMA|MOVBE */
-# define OSXSAVE_MASK (0x8000000|0x1000|0x400000)
+#ifndef bit_AVX2
+# define bit_AVX2 0x00000020
+#endif
+
+#ifndef bit_AVX512F
+# define bit_AVX512F 0x00010000
+#endif
+
+#ifndef bit_AVX512IFMA
+# define bit_AVX512IFMA 0x00200000
+#endif
+
+#ifndef bit_AVX512BW
+# define bit_AVX512BW 0x40000000
+#endif
+
+#ifndef bit_AVX512VL
+# define bit_AVX512VL 0x80000000
+#endif
+
+#ifndef bit_OSXSAVE
+# define bit_OSXSAVE 0x8000000
#endif
#ifndef bit_MOVBE
# define bit_MOVBE 0x00400000
#endif
+#ifndef OSXSAVE_MASK
+# define OSXSAVE_MASK (bit_OSXSAVE|bit_MOVBE)
+#endif
+
#define via_bit_PADLOCK (0x3 << 6)
#define via_bit_PADLOCK_PHE (0x3 << 10)
#define via_bit_PADLOCK_PHE_SHA512 (0x3 << 25)
@@ -127,7 +150,7 @@ static unsigned read_cpuid_vals(unsigned int vals[4])
unsigned t1, t2, t3;
vals[0] = vals[1] = vals[2] = vals[3] = 0;
- if (!__get_cpuid(1, &t1, &vals[0], &vals[1], &t2))
+ if (!__get_cpuid(1, &t1, &t2, &vals[1], &vals[0]))
return 0;
/* suppress AVX512; it works conditionally on certain CPUs on the original code */
vals[1] &= 0xfffff7ff;
@@ -145,7 +168,7 @@ static unsigned check_4th_gen_intel_features(unsigned ecx)
{
uint32_t xcr0;
- if ((ecx & OSXSAVE_MASK) != OSXSAVE_MASK)
+ if ((ecx & bit_OSXSAVE) != bit_OSXSAVE)
return 0;
#if defined(_MSC_VER) && !defined(__clang__)
@@ -233,10 +256,7 @@ static unsigned check_sha(void)
#ifdef ASM_X86_64
static unsigned check_avx_movbe(void)
{
- if (check_4th_gen_intel_features(_gnutls_x86_cpuid_s[1]) == 0)
- return 0;
-
- return ((_gnutls_x86_cpuid_s[1] & bit_AVX));
+ return (_gnutls_x86_cpuid_s[1] & bit_AVX);
}
static unsigned check_pclmul(void)
@@ -514,33 +534,47 @@ void register_x86_padlock_crypto(unsigned capabilities)
}
#endif
-static unsigned check_intel_or_amd(void)
+enum x86_cpu_vendor {
+ X86_CPU_VENDOR_OTHER,
+ X86_CPU_VENDOR_INTEL,
+ X86_CPU_VENDOR_AMD,
+};
+
+static enum x86_cpu_vendor check_x86_cpu_vendor(void)
{
unsigned int a, b, c, d;
- if (!__get_cpuid(0, &a, &b, &c, &d))
- return 0;
+ if (!__get_cpuid(0, &a, &b, &c, &d)) {
+ return X86_CPU_VENDOR_OTHER;
+ }
- if ((memcmp(&b, "Genu", 4) == 0 &&
- memcmp(&d, "ineI", 4) == 0 &&
- memcmp(&c, "ntel", 4) == 0) ||
- (memcmp(&b, "Auth", 4) == 0 &&
- memcmp(&d, "enti", 4) == 0 && memcmp(&c, "cAMD", 4) == 0)) {
- return 1;
+ if (memcmp(&b, "Genu", 4) == 0 &&
+ memcmp(&d, "ineI", 4) == 0 &&
+ memcmp(&c, "ntel", 4) == 0) {
+ return X86_CPU_VENDOR_INTEL;
}
- return 0;
+ if (memcmp(&b, "Auth", 4) == 0 &&
+ memcmp(&d, "enti", 4) == 0 &&
+ memcmp(&c, "cAMD", 4) == 0) {
+ return X86_CPU_VENDOR_AMD;
+ }
+
+ return X86_CPU_VENDOR_OTHER;
}
static
void register_x86_intel_crypto(unsigned capabilities)
{
int ret;
+ enum x86_cpu_vendor vendor;
memset(_gnutls_x86_cpuid_s, 0, sizeof(_gnutls_x86_cpuid_s));
- if (check_intel_or_amd() == 0)
+ vendor = check_x86_cpu_vendor();
+ if (vendor == X86_CPU_VENDOR_OTHER) {
return;
+ }
if (capabilities == 0) {
if (!read_cpuid_vals(_gnutls_x86_cpuid_s))
@@ -549,6 +583,23 @@ void register_x86_intel_crypto(unsigned capabilities)
capabilities_to_intel_cpuid(capabilities);
}
+ /* CRYPTOGAMS uses the (1 << 30) bit as an indicator of Intel CPUs */
+ if (vendor == X86_CPU_VENDOR_INTEL) {
+ _gnutls_x86_cpuid_s[0] |= 1 << 30;
+ } else {
+ _gnutls_x86_cpuid_s[0] &= ~(1 << 30);
+ }
+
+ if (!check_4th_gen_intel_features(_gnutls_x86_cpuid_s[1])) {
+ _gnutls_x86_cpuid_s[1] &= ~bit_AVX;
+
+ /* Clear AVX2 bits as well, according to what OpenSSL does.
+ * Should we clear bit_AVX512DQ, bit_AVX512PF, bit_AVX512ER, and
+ * bit_AVX512CD? */
+ _gnutls_x86_cpuid_s[2] &= ~(bit_AVX2|bit_AVX512F|bit_AVX512IFMA|
+ bit_AVX512BW|bit_AVX512BW);
+ }
+
if (check_ssse3()) {
_gnutls_debug_log("Intel SSSE3 was detected\n");
--
2.37.3
From cd509dac9e6d1bf76fd12c72c1fd61f1708c254a Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Mon, 15 Aug 2022 09:39:18 +0900
Subject: [PATCH 2/2] accelerated: clear AVX bits if it cannot be queried
through XSAVE
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The algorithm to detect AVX is described in 14.3 of "Intel® 64 and IA-32
Architectures Software Developers Manual".
GnuTLS previously only followed that algorithm when registering the
crypto backend, while the CRYPTOGAMS derived SHA code assembly expects
that the extension bits are propagated to _gnutls_x86_cpuid_s.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/accelerated/x86/x86-common.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/lib/accelerated/x86/x86-common.c b/lib/accelerated/x86/x86-common.c
index cf615ef24f..655d0c65f2 100644
--- a/lib/accelerated/x86/x86-common.c
+++ b/lib/accelerated/x86/x86-common.c
@@ -210,7 +210,8 @@ static void capabilities_to_intel_cpuid(unsigned capabilities)
}
if (capabilities & INTEL_AVX) {
- if ((a[1] & bit_AVX) && check_4th_gen_intel_features(a[1])) {
+ if ((a[1] & bit_AVX) && (a[1] & bit_MOVBE) &&
+ check_4th_gen_intel_features(a[1])) {
_gnutls_x86_cpuid_s[1] |= bit_AVX|bit_MOVBE;
} else {
_gnutls_debug_log
@@ -256,7 +257,7 @@ static unsigned check_sha(void)
#ifdef ASM_X86_64
static unsigned check_avx_movbe(void)
{
- return (_gnutls_x86_cpuid_s[1] & bit_AVX);
+ return (_gnutls_x86_cpuid_s[1] & (bit_AVX|bit_MOVBE)) == (bit_AVX|bit_MOVBE);
}
static unsigned check_pclmul(void)
@@ -579,6 +580,19 @@ void register_x86_intel_crypto(unsigned capabilities)
if (capabilities == 0) {
if (!read_cpuid_vals(_gnutls_x86_cpuid_s))
return;
+ if (!check_4th_gen_intel_features(_gnutls_x86_cpuid_s[1])) {
+ _gnutls_x86_cpuid_s[1] &= ~bit_AVX;
+
+ /* Clear AVX2 bits as well, according to what
+ * OpenSSL does. Should we clear
+ * bit_AVX512DQ, bit_AVX512PF, bit_AVX512ER,
+ * and bit_AVX512CD? */
+ _gnutls_x86_cpuid_s[2] &= ~(bit_AVX2|
+ bit_AVX512F|
+ bit_AVX512IFMA|
+ bit_AVX512BW|
+ bit_AVX512BW);
+ }
} else {
capabilities_to_intel_cpuid(capabilities);
}
--
2.37.3

View File

@ -1,38 +0,0 @@
commit 3b68043ef7e338118bce3ccdcbfafc8f005a6725
Author: Daiki Ueno <ueno@gnu.org>
Date: Mon Jul 7 10:44:12 2025 +0900
x509: avoid double free when exporting othernames in SAN
Previously, the _gnutls_write_new_othername function, called by
gnutls_x509_ext_export_subject_alt_names to export "otherName" in a
certificate's SAN extension, freed the caller allocated ASN.1
structure upon error, resulting in a potential double-free.
Reported by OpenAI Security Research Team.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
Backported-by: Alexander Sosedkin <asosedki@redhat.com>
Backported-from: 608829769cbc247679ffe98841109fc73875e573
Fixes: CVE-2025-32988
diff --git a/lib/x509/extensions.c b/lib/x509/extensions.c
index c9fef21a12..c0acdf9a94 100644
--- a/lib/x509/extensions.c
+++ b/lib/x509/extensions.c
@@ -805,7 +805,6 @@ _gnutls_write_new_othername(ASN1_TYPE ext, const char *ext_name,
result = asn1_write_value(ext, name2, oid, 1);
if (result != ASN1_SUCCESS) {
gnutls_assert();
- asn1_delete_structure(&ext);
return _gnutls_asn2err(result);
}
@@ -814,7 +813,6 @@ _gnutls_write_new_othername(ASN1_TYPE ext, const char *ext_name,
result = asn1_write_value(ext, name2, data, data_size);
if (result != ASN1_SUCCESS) {
gnutls_assert();
- asn1_delete_structure(&ext);
return _gnutls_asn2err(result);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,272 +0,0 @@
commit 8af3c1686d41b059f6f4b8352d36d9686cf7febe
Author: Daiki Ueno <ueno@gnu.org>
Date: Mon Jul 7 11:15:45 2025 +0900
handshake: clear HSK_PSK_SELECTED is when resetting binders
When a TLS 1.3 handshake involves HRR and resumption or PSK, and the
second Client Hello omits PSK, the server would result in a NULL
pointer dereference as the PSK binder information is cleared while the
HSK_PSK_SELECTED flag is still set. This makes sure that
HSK_PSK_SELECTED flag is always cleared when the PSK binders are
reset. This also makes it clear the HSK_PSK_SELECTED flag is valid
only during a handshake; after that, whether PSK is used can be
checked with gnutls_auth_client_get_type.
Reported by Stefan Bühler.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
Backported-by: Alexander Sosedkin <asosedki@redhat.com>
Backported-from: 23135619773e6ec087ff2abc65405bd4d5676bad
Fixes: CVE-2025-6395
diff --git a/lib/handshake.c b/lib/handshake.c
index ce2d160e20..b156223cbc 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -580,9 +580,28 @@ static int set_auth_types(gnutls_session_t session)
/* Under TLS1.3 this returns a KX which matches the negotiated
* groups from the key shares; if we are resuming then the KX seen
* here doesn't match the original session. */
- if (session->internals.resumed == RESUME_FALSE)
- kx = gnutls_kx_get(session);
- else
+ if (session->internals.resumed == RESUME_FALSE) {
+ const gnutls_group_entry_st *group = get_group(session);
+
+ if (session->internals.hsk_flags & HSK_PSK_SELECTED) {
+ if (group) {
+ kx = group->pk == GNUTLS_PK_DH ?
+ GNUTLS_KX_DHE_PSK :
+ GNUTLS_KX_ECDHE_PSK;
+ } else {
+ kx = GNUTLS_KX_PSK;
+ }
+ } else if (group) {
+ /* Not necessarily be RSA, but just to
+ * make _gnutls_map_kx_get_cred below
+ * work.
+ */
+ kx = group->pk == GNUTLS_PK_DH ?
+ GNUTLS_KX_DHE_RSA :
+ GNUTLS_KX_ECDHE_RSA;
+ } else
+ kx = GNUTLS_KX_UNKNOWN;
+ } else
kx = GNUTLS_KX_UNKNOWN;
} else {
/* TLS1.2 or earlier, kx is associated with ciphersuite */
diff --git a/lib/state.c b/lib/state.c
index 817a7b8cd8..2bd08c3190 100644
--- a/lib/state.c
+++ b/lib/state.c
@@ -175,7 +175,8 @@ gnutls_kx_algorithm_t gnutls_kx_get(gnutls_session_t session)
const gnutls_group_entry_st *group = get_group(session);
if (ver->tls13_sem) {
- if (session->internals.hsk_flags & HSK_PSK_SELECTED) {
+ if (gnutls_auth_client_get_type(session) ==
+ GNUTLS_CRD_PSK) {
if (group) {
if (group->pk == GNUTLS_PK_DH)
return GNUTLS_KX_DHE_PSK;
@@ -264,6 +265,7 @@ void reset_binders(gnutls_session_t session)
_gnutls_free_temp_key_datum(&session->key.binders[0].psk);
_gnutls_free_temp_key_datum(&session->key.binders[1].psk);
memset(session->key.binders, 0, sizeof(session->key.binders));
+ session->internals.hsk_flags &= ~HSK_PSK_SELECTED;
}
/* Check whether certificate credentials of type @cert_type are set
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b04cb081b4..1019f6c1d8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -118,6 +118,8 @@ ctests = tls13/supported_versions tls13/tls12-no-tls13-exts \
ctests += tls13/hello_retry_request
+ctests += tls13/hello_retry_request_psk
+
ctests += tls13/psk-ext
ctests += tls13/key_update
diff --git a/tests/tls13/hello_retry_request_psk.c b/tests/tls13/hello_retry_request_psk.c
new file mode 100644
index 0000000000..a20cb0d965
--- /dev/null
+++ b/tests/tls13/hello_retry_request_psk.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2017-2025 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos, Daiki Ueno
+ *
+ * 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>
+#include <stdint.h>
+
+#include <string.h>
+#include <gnutls/gnutls.h>
+#include <assert.h>
+
+#include "cert-common.h"
+#include "utils.h"
+#include "tls13/ext-parse.h"
+#include "eagain-common.h"
+
+/* This program exercises the case where a TLS 1.3 handshake ends up
+ * with HRR, and the first CH includes PSK while the 2nd CH omits
+ * it */
+
+const char *testname = "hello entry request";
+
+const char *side = "";
+
+#define myfail(fmt, ...) fail("%s: " fmt, testname, ##__VA_ARGS__)
+
+static void tls_log_func(int level, const char *str)
+{
+ fprintf(stderr, "%s|<%d>| %s", side, level, str);
+}
+
+struct ctx_st {
+ unsigned hrr_seen;
+ unsigned hello_counter;
+};
+
+static int pskfunc(gnutls_session_t session, const char *username,
+ gnutls_datum_t *key)
+{
+ if (debug)
+ printf("psk: username %s\n", username);
+ key->data = gnutls_malloc(4);
+ key->data[0] = 0xDE;
+ key->data[1] = 0xAD;
+ key->data[2] = 0xBE;
+ key->data[3] = 0xEF;
+ key->size = 4;
+ return 0;
+}
+
+static int hello_callback(gnutls_session_t session, unsigned int htype,
+ unsigned post, unsigned int incoming,
+ const gnutls_datum_t *msg)
+{
+ struct ctx_st *ctx = gnutls_session_get_ptr(session);
+ assert(ctx != NULL);
+
+ if (htype == GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST)
+ ctx->hrr_seen = 1;
+
+ if (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO) {
+ if (post == GNUTLS_HOOK_POST)
+ ctx->hello_counter++;
+ else {
+ /* Unset the PSK credential to omit the extension */
+ gnutls_credentials_set(session, GNUTLS_CRD_PSK, NULL);
+ }
+ }
+
+ return 0;
+}
+
+void doit(void)
+{
+ int sret, cret;
+ gnutls_psk_server_credentials_t scred;
+ gnutls_psk_client_credentials_t ccred;
+ gnutls_certificate_credentials_t ccred2;
+ gnutls_session_t server, client;
+ /* Need to enable anonymous KX specifically. */
+ const gnutls_datum_t key = { (void *)"DEADBEEF", 8 };
+
+ struct ctx_st ctx;
+ memset(&ctx, 0, sizeof(ctx));
+
+ global_init();
+
+ gnutls_global_set_log_function(tls_log_func);
+ if (debug)
+ gnutls_global_set_log_level(9);
+
+ /* Init server */
+ assert(gnutls_psk_allocate_server_credentials(&scred) >= 0);
+ gnutls_psk_set_server_credentials_function(scred, pskfunc);
+
+ gnutls_init(&server, GNUTLS_SERVER);
+
+ assert(gnutls_priority_set_direct(
+ server,
+ "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-X25519:+DHE-PSK",
+ NULL) >= 0);
+
+ gnutls_credentials_set(server, GNUTLS_CRD_PSK, scred);
+ gnutls_transport_set_push_function(server, server_push);
+ gnutls_transport_set_pull_function(server, server_pull);
+ gnutls_transport_set_ptr(server, server);
+
+ /* Init client */
+ assert(gnutls_psk_allocate_client_credentials(&ccred) >= 0);
+ gnutls_psk_set_client_credentials(ccred, "test", &key,
+ GNUTLS_PSK_KEY_HEX);
+ assert(gnutls_certificate_allocate_credentials(&ccred2) >= 0);
+
+ assert(gnutls_init(&client, GNUTLS_CLIENT | GNUTLS_KEY_SHARE_TOP) >= 0);
+
+ gnutls_session_set_ptr(client, &ctx);
+
+ cret = gnutls_priority_set_direct(
+ client,
+ "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP256R1:+GROUP-X25519:+DHE-PSK",
+ NULL);
+ if (cret < 0)
+ myfail("cannot set TLS 1.3 priorities\n");
+
+ gnutls_credentials_set(client, GNUTLS_CRD_PSK, ccred);
+ gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, ccred2);
+ gnutls_transport_set_push_function(client, client_push);
+ gnutls_transport_set_pull_function(client, client_pull);
+ gnutls_transport_set_ptr(client, client);
+
+ gnutls_handshake_set_hook_function(client, GNUTLS_HANDSHAKE_ANY,
+ GNUTLS_HOOK_BOTH, hello_callback);
+
+ HANDSHAKE_EXPECT(client, server, GNUTLS_E_AGAIN,
+ GNUTLS_E_INSUFFICIENT_CREDENTIALS);
+
+ assert(ctx.hrr_seen != 0);
+
+ gnutls_bye(client, GNUTLS_SHUT_WR);
+ gnutls_bye(server, GNUTLS_SHUT_WR);
+
+ gnutls_deinit(client);
+ gnutls_deinit(server);
+
+ gnutls_psk_free_server_credentials(scred);
+ gnutls_psk_free_client_credentials(ccred);
+ gnutls_certificate_free_credentials(ccred2);
+
+ gnutls_global_deinit();
+ reset_buffers();
+}

View File

@ -1,474 +0,0 @@
From 0d39e4120bc5ece53c86c5802c546259b8ca286a Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Fri, 12 Jan 2024 17:56:58 +0900
Subject: [PATCH] nettle: avoid normalization of mpz_t in deterministic ECDSA
This removes function calls that potentially leak bit-length of a
private key used to calculate a nonce in deterministic ECDSA. Namely:
- _gnutls_dsa_compute_k has been rewritten to work on always
zero-padded mp_limb_t arrays instead of mpz_t
- rnd_mpz_func has been replaced with rnd_datum_func, which is backed
by a byte array instead of an mpz_t value
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/nettle/int/dsa-compute-k.c | 84 +++++++++++++++++++------------
lib/nettle/int/dsa-compute-k.h | 31 +++++++++---
lib/nettle/int/ecdsa-compute-k.c | 71 +++++++++-----------------
lib/nettle/int/ecdsa-compute-k.h | 8 +--
lib/nettle/pk.c | 79 ++++++++++++++++++++---------
tests/sign-verify-deterministic.c | 2 +-
6 files changed, 158 insertions(+), 117 deletions(-)
diff --git a/lib/nettle/int/dsa-compute-k.c b/lib/nettle/int/dsa-compute-k.c
index 17d63318c4..ddeb6f6d1e 100644
--- a/lib/nettle/int/dsa-compute-k.c
+++ b/lib/nettle/int/dsa-compute-k.c
@@ -31,33 +31,37 @@
#include "mpn-base256.h"
#include <string.h>
-#define BITS_TO_LIMBS(bits) (((bits) + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
-
-/* The maximum size of q, choosen from the fact that we support
- * 521-bit elliptic curve generator and 512-bit DSA subgroup at
- * maximum. */
-#define MAX_Q_BITS 521
-#define MAX_Q_SIZE ((MAX_Q_BITS + 7) / 8)
-#define MAX_Q_LIMBS BITS_TO_LIMBS(MAX_Q_BITS)
-
-#define MAX_HASH_BITS (MAX_HASH_SIZE * 8)
-#define MAX_HASH_LIMBS BITS_TO_LIMBS(MAX_HASH_BITS)
-
-int
-_gnutls_dsa_compute_k(mpz_t k,
- const mpz_t q,
- const mpz_t x,
- gnutls_mac_algorithm_t mac,
- const uint8_t *digest,
- size_t length)
+/* For mini-gmp */
+#ifndef GMP_LIMB_BITS
+#define GMP_LIMB_BITS GMP_NUMB_BITS
+#endif
+
+static inline int is_zero_limb(mp_limb_t x)
+{
+ x |= (x << 1);
+ return ((x >> 1) - 1) >> (GMP_LIMB_BITS - 1);
+}
+
+static int sec_zero_p(const mp_limb_t *ap, mp_size_t n)
+{
+ volatile mp_limb_t w;
+ mp_size_t i;
+
+ for (i = 0, w = 0; i < n; i++)
+ w |= ap[i];
+
+ return is_zero_limb(w);
+}
+
+int _gnutls_dsa_compute_k(mp_limb_t *h, const mp_limb_t *q, const mp_limb_t *x,
+ mp_size_t qn, mp_bitcnt_t q_bits,
+ gnutls_mac_algorithm_t mac, const uint8_t *digest,
+ size_t length)
{
uint8_t V[MAX_HASH_SIZE];
uint8_t K[MAX_HASH_SIZE];
uint8_t xp[MAX_Q_SIZE];
uint8_t tp[MAX_Q_SIZE];
- mp_limb_t h[MAX(MAX_Q_LIMBS, MAX_HASH_LIMBS)];
- mp_bitcnt_t q_bits = mpz_sizeinbase (q, 2);
- mp_size_t qn = mpz_size(q);
mp_bitcnt_t h_bits = length * 8;
mp_size_t hn = BITS_TO_LIMBS(h_bits);
size_t nbytes = (q_bits + 7) / 8;
@@ -66,6 +70,7 @@ _gnutls_dsa_compute_k(mpz_t k,
mp_limb_t cy;
gnutls_hmac_hd_t hd;
int ret = 0;
+ mp_limb_t scratch[MAX_Q_LIMBS];
if (unlikely(q_bits > MAX_Q_BITS))
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
@@ -73,7 +78,7 @@ _gnutls_dsa_compute_k(mpz_t k,
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
/* int2octets(x) */
- mpn_get_base256(xp, nbytes, mpz_limbs_read(x), qn);
+ mpn_get_base256(xp, nbytes, x, qn);
/* bits2octets(h) */
mpn_set_base256(h, hn, digest, length);
@@ -97,12 +102,12 @@ _gnutls_dsa_compute_k(mpz_t k,
mpn_rshift(h, h, hn, shift % GMP_NUMB_BITS);
}
- cy = mpn_sub_n(h, h, mpz_limbs_read(q), qn);
+ cy = mpn_sub_n(h, h, q, qn);
/* Fall back to addmul_1, if nettle is linked with mini-gmp. */
#ifdef mpn_cnd_add_n
- mpn_cnd_add_n(cy, h, h, mpz_limbs_read(q), qn);
+ mpn_cnd_add_n(cy, h, h, q, qn);
#else
- mpn_addmul_1(h, mpz_limbs_read(q), qn, cy != 0);
+ mpn_addmul_1(h, q, qn, cy != 0);
#endif
mpn_get_base256(tp, nbytes, h, qn);
@@ -178,12 +183,8 @@ _gnutls_dsa_compute_k(mpz_t k,
if (tlen * 8 > q_bits)
mpn_rshift (h, h, qn, tlen * 8 - q_bits);
/* Check if k is in [1,q-1] */
- if (!mpn_zero_p (h, qn) &&
- mpn_cmp (h, mpz_limbs_read(q), qn) < 0) {
- mpn_copyi(mpz_limbs_write(k, qn), h, qn);
- mpz_limbs_finish(k, qn);
+ if (!sec_zero_p(h, qn) && mpn_sub_n(scratch, h, q, qn))
break;
- }
ret = gnutls_hmac_init(&hd, mac, K, length);
if (ret < 0)
@@ -207,3 +208,24 @@ _gnutls_dsa_compute_k(mpz_t k,
return ret;
}
+
+/* cancel-out dsa_sign's addition of 1 to random data */
+void _gnutls_dsa_compute_k_finish(uint8_t *k, size_t nbytes, mp_limb_t *h,
+ mp_size_t n)
+{
+ /* Fall back to sub_1, if nettle is linked with mini-gmp. */
+#ifdef mpn_sec_sub_1
+ mp_limb_t t[MAX_Q_LIMBS];
+
+ mpn_sec_sub_1(h, h, n, 1, t);
+#else
+ mpn_sub_1(h, h, n, 1);
+#endif
+ mpn_get_base256(k, nbytes, h, n);
+}
+
+void _gnutls_ecdsa_compute_k_finish(uint8_t *k, size_t nbytes, mp_limb_t *h,
+ mp_size_t n)
+{
+ mpn_get_base256(k, nbytes, h, n);
+}
diff --git a/lib/nettle/int/dsa-compute-k.h b/lib/nettle/int/dsa-compute-k.h
index 64e90e0ca2..e88fce0a6d 100644
--- a/lib/nettle/int/dsa-compute-k.h
+++ b/lib/nettle/int/dsa-compute-k.h
@@ -26,12 +26,29 @@
#include <gnutls/gnutls.h>
#include <nettle/bignum.h> /* includes gmp.h */
-int
-_gnutls_dsa_compute_k(mpz_t k,
- const mpz_t q,
- const mpz_t x,
- gnutls_mac_algorithm_t mac,
- const uint8_t *digest,
- size_t length);
+#define BITS_TO_LIMBS(bits) (((bits) + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
+
+/* The maximum size of q, chosen from the fact that we support
+ * 521-bit elliptic curve generator and 512-bit DSA subgroup at
+ * maximum. */
+#define MAX_Q_BITS 521
+#define MAX_Q_SIZE ((MAX_Q_BITS + 7) / 8)
+#define MAX_Q_LIMBS BITS_TO_LIMBS(MAX_Q_BITS)
+
+#define MAX_HASH_BITS (MAX_HASH_SIZE * 8)
+#define MAX_HASH_LIMBS BITS_TO_LIMBS(MAX_HASH_BITS)
+
+#define DSA_COMPUTE_K_ITCH MAX(MAX_Q_LIMBS, MAX_HASH_LIMBS)
+
+int _gnutls_dsa_compute_k(mp_limb_t *h, const mp_limb_t *q, const mp_limb_t *x,
+ mp_size_t qn, mp_bitcnt_t q_bits,
+ gnutls_mac_algorithm_t mac, const uint8_t *digest,
+ size_t length);
+
+void _gnutls_dsa_compute_k_finish(uint8_t *k, size_t nbytes, mp_limb_t *h,
+ mp_size_t n);
+
+void _gnutls_ecdsa_compute_k_finish(uint8_t *k, size_t nbytes, mp_limb_t *h,
+ mp_size_t n);
#endif /* GNUTLS_LIB_NETTLE_INT_DSA_COMPUTE_K_H */
diff --git a/lib/nettle/int/ecdsa-compute-k.c b/lib/nettle/int/ecdsa-compute-k.c
index 94914ebdfa..819302c1c7 100644
--- a/lib/nettle/int/ecdsa-compute-k.c
+++ b/lib/nettle/int/ecdsa-compute-k.c
@@ -29,67 +29,46 @@
#include "dsa-compute-k.h"
#include "gnutls_int.h"
-static inline int
-_gnutls_ecc_curve_to_dsa_q(mpz_t *q, gnutls_ecc_curve_t curve)
+int _gnutls_ecc_curve_to_dsa_q(mpz_t q, gnutls_ecc_curve_t curve)
{
switch (curve) {
#ifdef ENABLE_NON_SUITEB_CURVES
case GNUTLS_ECC_CURVE_SECP192R1:
- mpz_init_set_str(*q,
- "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836"
- "146BC9B1B4D22831",
- 16);
+ mpz_set_str(q,
+ "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836"
+ "146BC9B1B4D22831",
+ 16);
return 0;
case GNUTLS_ECC_CURVE_SECP224R1:
- mpz_init_set_str(*q,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2"
- "E0B8F03E13DD29455C5C2A3D",
- 16);
+ mpz_set_str(q,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2"
+ "E0B8F03E13DD29455C5C2A3D",
+ 16);
return 0;
#endif
case GNUTLS_ECC_CURVE_SECP256R1:
- mpz_init_set_str(*q,
- "FFFFFFFF00000000FFFFFFFFFFFFFFFF"
- "BCE6FAADA7179E84F3B9CAC2FC632551",
- 16);
+ mpz_set_str(q,
+ "FFFFFFFF00000000FFFFFFFFFFFFFFFF"
+ "BCE6FAADA7179E84F3B9CAC2FC632551",
+ 16);
return 0;
case GNUTLS_ECC_CURVE_SECP384R1:
- mpz_init_set_str(*q,
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
- "FFFFFFFFFFFFFFFFC7634D81F4372DDF"
- "581A0DB248B0A77AECEC196ACCC52973",
- 16);
+ mpz_set_str(q,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ "FFFFFFFFFFFFFFFFC7634D81F4372DDF"
+ "581A0DB248B0A77AECEC196ACCC52973",
+ 16);
return 0;
case GNUTLS_ECC_CURVE_SECP521R1:
- mpz_init_set_str(*q,
- "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
- "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
- "FFA51868783BF2F966B7FCC0148F709A"
- "5D03BB5C9B8899C47AEBB6FB71E91386"
- "409",
- 16);
+ mpz_set_str(q,
+ "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+ "FFA51868783BF2F966B7FCC0148F709A"
+ "5D03BB5C9B8899C47AEBB6FB71E91386"
+ "409",
+ 16);
return 0;
default:
return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM);
}
}
-
-int
-_gnutls_ecdsa_compute_k (mpz_t k,
- gnutls_ecc_curve_t curve,
- const mpz_t x,
- gnutls_mac_algorithm_t mac,
- const uint8_t *digest,
- size_t length)
-{
- mpz_t q;
- int ret;
-
- ret = _gnutls_ecc_curve_to_dsa_q(&q, curve);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- ret = _gnutls_dsa_compute_k (k, q, x, mac, digest, length);
- mpz_clear(q);
- return ret;
-}
diff --git a/lib/nettle/int/ecdsa-compute-k.h b/lib/nettle/int/ecdsa-compute-k.h
index 7ca401d6e4..a7e612bcab 100644
--- a/lib/nettle/int/ecdsa-compute-k.h
+++ b/lib/nettle/int/ecdsa-compute-k.h
@@ -26,12 +26,6 @@
#include <gnutls/gnutls.h>
#include <nettle/bignum.h> /* includes gmp.h */
-int
-_gnutls_ecdsa_compute_k (mpz_t k,
- gnutls_ecc_curve_t curve,
- const mpz_t x,
- gnutls_mac_algorithm_t mac,
- const uint8_t *digest,
- size_t length);
+int _gnutls_ecc_curve_to_dsa_q(mpz_t q, gnutls_ecc_curve_t curve);
#endif /* GNUTLS_LIB_NETTLE_INT_ECDSA_COMPUTE_K_H */
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index 588e9df502..b19fe3804a 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -102,10 +102,16 @@ static void rnd_nonce_func(void *_ctx, size_t length, uint8_t * data)
}
}
-static void rnd_mpz_func(void *_ctx, size_t length, uint8_t * data)
+static void rnd_datum_func(void *ctx, size_t length, uint8_t *data)
{
- mpz_t *k = _ctx;
- nettle_mpz_get_str_256 (length, data, *k);
+ gnutls_datum_t *d = ctx;
+
+ if (length > d->size) {
+ memset(data, 0, length - d->size);
+ memcpy(data + (length - d->size), d->data, d->size);
+ } else {
+ memcpy(data, d->data, length);
+ }
}
static void rnd_nonce_func_fallback(void *_ctx, size_t length, uint8_t * data)
@@ -976,7 +982,10 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
struct dsa_signature sig;
int curve_id = pk_params->curve;
const struct ecc_curve *curve;
- mpz_t k;
+ mpz_t q;
+ /* 521-bit elliptic curve generator at maximum */
+ uint8_t buf[(521 + 7) / 8];
+ gnutls_datum_t k = { NULL, 0 };
void *random_ctx;
nettle_random_func *random_func;
@@ -1005,19 +1014,32 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
hash_len = vdata->size;
}
- mpz_init(k);
+ mpz_init(q);
+
if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST ||
(sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE)) {
- ret = _gnutls_ecdsa_compute_k(k,
- curve_id,
- pk_params->params[ECC_K],
- DIG_TO_MAC(sign_params->dsa_dig),
- vdata->data,
- vdata->size);
+ mp_limb_t h[DSA_COMPUTE_K_ITCH];
+
+ ret = _gnutls_ecc_curve_to_dsa_q(q, curve_id);
if (ret < 0)
goto ecdsa_cleanup;
+
+ ret = _gnutls_dsa_compute_k(
+ h, mpz_limbs_read(q), priv.p,
+ ecc_size(priv.ecc), ecc_bit_size(priv.ecc),
+ DIG_TO_MAC(sign_params->dsa_dig), vdata->data,
+ vdata->size);
+ if (ret < 0)
+ goto ecdsa_cleanup;
+
+ k.data = buf;
+ k.size = (ecc_bit_size(priv.ecc) + 7) / 8;
+
+ _gnutls_ecdsa_compute_k_finish(k.data, k.size, h,
+ ecc_size(priv.ecc));
+
random_ctx = &k;
- random_func = rnd_mpz_func;
+ random_func = rnd_datum_func;
} else {
random_ctx = NULL;
random_func = rnd_nonce_func;
@@ -1038,7 +1060,7 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
ecdsa_cleanup:
dsa_signature_clear(&sig);
ecc_scalar_zclear(&priv);
- mpz_clear(k);
+ mpz_clear(q);
if (ret < 0) {
gnutls_assert();
@@ -1051,7 +1073,9 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
struct dsa_params pub;
bigint_t priv;
struct dsa_signature sig;
- mpz_t k;
+ /* 512-bit DSA subgroup at maximum */
+ uint8_t buf[(512 + 7) / 8];
+ gnutls_datum_t k = { NULL, 0 };
void *random_ctx;
nettle_random_func *random_func;
@@ -1074,21 +1098,27 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
hash_len = vdata->size;
}
- mpz_init(k);
if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST ||
(sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE)) {
- ret = _gnutls_dsa_compute_k(k,
- pub.q,
- TOMPZ(priv),
- DIG_TO_MAC(sign_params->dsa_dig),
- vdata->data,
- vdata->size);
+ mp_limb_t h[DSA_COMPUTE_K_ITCH];
+
+ ret = _gnutls_dsa_compute_k(
+ h, mpz_limbs_read(pub.q),
+ mpz_limbs_read(TOMPZ(priv)), mpz_size(pub.q),
+ mpz_sizeinbase(pub.q, 2),
+ DIG_TO_MAC(sign_params->dsa_dig), vdata->data,
+ vdata->size);
if (ret < 0)
goto dsa_fail;
- /* cancel-out dsa_sign's addition of 1 to random data */
- mpz_sub_ui (k, k, 1);
+
+ k.data = buf;
+ k.size = (mpz_sizeinbase(pub.q, 2) + 7) / 8;
+
+ _gnutls_dsa_compute_k_finish(k.data, k.size, h,
+ mpz_size(pub.q));
+
random_ctx = &k;
- random_func = rnd_mpz_func;
+ random_func = rnd_datum_func;
} else {
random_ctx = NULL;
random_func = rnd_nonce_func;
@@ -1108,7 +1138,6 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
dsa_fail:
dsa_signature_clear(&sig);
- mpz_clear(k);
if (ret < 0) {
gnutls_assert();
diff --git a/tests/sign-verify-deterministic.c b/tests/sign-verify-deterministic.c
index 6e907288ee..25aa553a59 100644
--- a/tests/sign-verify-deterministic.c
+++ b/tests/sign-verify-deterministic.c
@@ -197,7 +197,7 @@ void doit(void)
&signature);
if (ret < 0)
testfail("gnutls_pubkey_verify_data2\n");
- success(" - pass");
+ success(" - pass\n");
next:
gnutls_free(signature.data);
--
2.44.0

View File

@ -1,14 +0,0 @@
--- gnutls-3.7.2/doc/manpages/p11tool.1 2021-05-29 10:15:22.000000000 +0200
+++ gnutls-3.7.2-bootstrapped/doc/manpages/p11tool.1 2021-06-28 09:35:23.000000000 +0200
@@ -230,8 +230,9 @@
.NOP \f\*[B-Font]\-\-write\f[]
Writes the loaded objects to a PKCS #11 token.
.sp
-It can be used to write private, public keys, certificates or secret keys to a token. Must be combined with
- one of \--load-privkey, \--load-pubkey, \--load-certificate option.
+It can be used to write private, public keys, certificates or secret keys to a token. Must be combined with one of \--load-privkey, \--load-pubkey, \--load-certificate option.
+.sp
+When writing a certificate object, its CKA_ID is set to the same CKA_ID of the corresponding public key, if it exists on the token; otherwise it will be derived from the X.509 Subject Key Identifier of the certificate. If this behavior is undesired, write the public key to the token beforehand.
.TP
.NOP \f\*[B-Font]\-\-delete\f[]
Deletes the objects matching the given PKCS #11 URL.

View File

@ -1,266 +0,0 @@
From e5dc27d1a457d1b3abc0582cd133910dff0fc309 Mon Sep 17 00:00:00 2001
From: Zoltan Fridrich <zfridric@redhat.com>
Date: Fri, 22 Jul 2022 12:00:11 +0200
Subject: [PATCH] Fix double free during gnutls_pkcs7_verify
Signed-off-by: Zoltan Fridrich <zfridric@redhat.com>
---
.gitignore | 1 +
lib/x509/pkcs7.c | 3 +-
tests/Makefile.am | 3 +-
tests/pkcs7-verify-double-free.c | 215 +++++++++++++++++++++++++++++++
4 files changed, 220 insertions(+), 2 deletions(-)
create mode 100644 tests/pkcs7-verify-double-free.c
diff --git a/lib/x509/pkcs7.c b/lib/x509/pkcs7.c
index 0ff55ba04b..878f867862 100644
--- a/lib/x509/pkcs7.c
+++ b/lib/x509/pkcs7.c
@@ -1318,7 +1318,8 @@ gnutls_x509_crt_t find_signer(gnutls_pkcs7_t pkcs7, gnutls_x509_trust_list_t tl,
issuer = find_verified_issuer_of(pkcs7, issuer, purpose, vflags);
if (issuer != NULL && gnutls_x509_crt_check_issuer(issuer, issuer)) {
- if (prev) gnutls_x509_crt_deinit(prev);
+ if (prev && prev != signer)
+ gnutls_x509_crt_deinit(prev);
prev = issuer;
break;
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b04cb081b4..0563d3c754 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -220,7 +220,8 @@ ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniquei
sign-verify-newapi sign-verify-deterministic iov aead-cipher-vec \
tls13-without-timeout-func buffer status-request-revoked \
set_x509_ocsp_multi_cli kdf-api keylog-func \
- dtls_hello_random_value tls_hello_random_value x509cert-dntypes
+ dtls_hello_random_value tls_hello_random_value x509cert-dntypes \
+ pkcs7-verify-double-free
if HAVE_SECCOMP_TESTS
ctests += dtls-with-seccomp tls-with-seccomp dtls-client-with-seccomp tls-client-with-seccomp
diff --git a/tests/pkcs7-verify-double-free.c b/tests/pkcs7-verify-double-free.c
new file mode 100644
index 0000000000..fadf307829
--- /dev/null
+++ b/tests/pkcs7-verify-double-free.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Zoltan Fridrich
+ *
+ * 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 General Public License
+ * along with GnuTLS. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <gnutls/pkcs7.h>
+#include <gnutls/x509.h>
+
+#include "utils.h"
+
+static char rca_pem[] =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDCjCCAfKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQKDApFeGFt\n"
+ "cGxlIENBMCAXDTE3MDcyMTE0NDMzNloYDzIyMjIwNzIxMTQ0MzM2WjAVMRMwEQYD\n"
+ "VQQKDApFeGFtcGxlIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n"
+ "v8hnKPJ/IA0SQB/A/a0Uh+npZ67vsgIMrtTQo0r0kJkmkBz5323xO3DVuJfB3QmX\n"
+ "v9zvoeCQLuDvWar5Aixfxgm6s5Q+yPvJj9t3NebDrU+Y4+qyewBIJUF8EF/5iBPC\n"
+ "ZHONmzbfIRWvQWGGgb2CRcOHp2J7AY/QLB6LsWPaLjs/DHva28Q13JaTTHIpdu8v\n"
+ "t6vHr0nXf66DN4MvtoF3N+o+v3snJCMsfXOqASi4tbWR7gtOfCfiz9uBjh0W2Dut\n"
+ "/jclBQkJkLe6esNSM+f4YiOpctVDjmfj8yoHCp394vt0wFqhG38wsTFAyVP6qIcf\n"
+ "5zoSu9ovEt2cTkhnZHjiiwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud\n"
+ "DwEB/wQEAwIBBjAdBgNVHQ4EFgQUhjeO6Uc5imbjOl2I2ltVA27Hu9YwHwYDVR0j\n"
+ "BBgwFoAUhjeO6Uc5imbjOl2I2ltVA27Hu9YwDQYJKoZIhvcNAQELBQADggEBAD+r\n"
+ "i/7FsbG0OFKGF2+JOnth6NjJQcMfM8LiglqAuBUijrv7vltoZ0Z3FJH1Vi4OeMXn\n"
+ "l7X/9tWUve0uFl75MfjDrf0+lCEdYRY1LCba2BrUgpbbkLywVUdnbsvndehegCgS\n"
+ "jss2/zys3Hlo3ZaHlTMQ/NQ4nrxcxkjOvkZSEOqgxJTLpzm6pr7YUts4k6c6lNiB\n"
+ "FSiJiDzsJCmWR9C3fBbUlfDfTJYGN3JwqX270KchXDElo8gNoDnF7jBMpLFFSEKm\n"
+ "MyfbNLX/srh+CEfZaN/OZV4A3MQ0L8vQEp6M4CJhvRLIuMVabZ2coJ0AzystrOMU\n"
+ "LirBWjg89RoAjFQ7bTE=\n"
+ "-----END CERTIFICATE-----\n";
+
+static char ca_pem[] =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDFzCCAf+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQKDApFeGFt\n"
+ "cGxlIENBMCAXDTE3MDcyMTE0NDQzNFoYDzIyMjIwNzIxMTQ0NDM0WjAiMSAwHgYD\n"
+ "VQQKDBdFeGFtcGxlIGludGVybWVkaWF0ZSBDQTCCASIwDQYJKoZIhvcNAQEBBQAD\n"
+ "ggEPADCCAQoCggEBAKb9ACB8u//sP6MfNU1OsVw68xz3eTPLgKxS0vpqexm6iGVg\n"
+ "ug/o9uYRLzqiEukv/eyz9WzHmY7sqlOJjOFdv92+SaNg79Jc51WHPFXgea4/qyfr\n"
+ "4y14PGs0SNxm6T44sXurUs7cXydQVUgnq2VCaWFOTUdxXoAWkV8r8GaUoPD/klVz\n"
+ "RqxSZVETmX1XBKhsMnnov41kRwVph2C+VfUspsbaUZaz/o/S1/nokhXRACzKsMBr\n"
+ "obqiGxbY35uVzsmbAW5ErhQz98AWJL3Bub1fsEMXg6OEMmPH4AtX888dTIYZNw0E\n"
+ "bUIESspz1kjJQTtVQDHTprhwz16YiSVeUonlLgMCAwEAAaNjMGEwDwYDVR0TAQH/\n"
+ "BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPBjxDWjMhjXERirKF9O\n"
+ "o/5Cllc5MB8GA1UdIwQYMBaAFIY3julHOYpm4zpdiNpbVQNux7vWMA0GCSqGSIb3\n"
+ "DQEBCwUAA4IBAQCTm+vv3hBa6lL5IT+Fw8aTxQ2Ne7mZ5oyazhvXYwwfKNMX3SML\n"
+ "W2JdPaL64ZwbxxxYvW401o5Z0CEgru3YFrsqB/hEdl0Uf8UWWJmE1rRa+miTmbjt\n"
+ "lrLNCWdrs6CiwvsPITTHg7jevB4KyZYsTSxQFcyr3N3xF+6EmOTC4IkhPPnXYXcp\n"
+ "248ih+WOavSYoRvzgB/Dip1WnPYU2mfIV3O8JReRryngA0TzWCLPLUoWR3R4jwtC\n"
+ "+1uSLoqaenz3qv3F1WEbke37az9YJuXx/5D8CqFQiZ62TUUtI6fYd8mkMBM4Qfh6\n"
+ "NW9XrCkI9wlpL5K9HllhuW0BhKeJkuPpyQ2p\n"
+ "-----END CERTIFICATE-----\n";
+
+static char ee_pem[] =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDIjCCAgqgAwIBAgIBATANBgkqhkiG9w0BAQsFADAiMSAwHgYDVQQKDBdFeGFt\n"
+ "cGxlIGludGVybWVkaWF0ZSBDQTAgFw0yMjA3MjExNDQ1MzdaGA8yMjIyMDcyMTE0\n"
+ "NDUzN1owFTETMBEGA1UEAwwKSm9obiBTbWl0aDCCASIwDQYJKoZIhvcNAQEBBQAD\n"
+ "ggEPADCCAQoCggEBAMb1uuxppBFY+WVD45iyHUq7DkIJNNOI/JRaybVJfPktWq2E\n"
+ "eNe7XhV05KKnqZTbDO2iYqNHqGhZ8pz/IstDRTZP3z/q1vXTG0P9Gx28rEy5TaUY\n"
+ "QjtD+ZoFUQm0ORMDBjd8jikqtJ87hKeuOPMH4rzdydotMaPQSm7KLzHBGBr6gg7z\n"
+ "g1IxPWkhMyHapoMqqrhjwjzoTY97UIXpZTEoIA+KpEC8f9CciBtL0i1MPBjWozB6\n"
+ "Jma9q5iEwZXuRr3cnPYeIPlK2drgDZCMuSFcYiT8ApLw5OhKqY1m2EvfZ2ox2s9R\n"
+ "68/HzYdPi3kZwiNEtlBvMlpt5yKBJAflp76d7DkCAwEAAaNuMGwwCwYDVR0PBAQD\n"
+ "AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAdBgNVHQ4EFgQUc+Mi\n"
+ "kr8WMCk00SQo+P2iggp/oQkwHwYDVR0jBBgwFoAU8GPENaMyGNcRGKsoX06j/kKW\n"
+ "VzkwDQYJKoZIhvcNAQELBQADggEBAKU9+CUR0Jcfybd1+8Aqgh1RH96yQygnVuyt\n"
+ "Na9rFz4fM3ij9tGXDHXrkZw8bW1dWLU9quu8zeTxKxc3aiDIw739Alz0tukttDo7\n"
+ "dW7YqIb77zsIsWB9p7G9dlxT6ieUy+5IKk69BbeK8KR0vAciAG4KVQxPhuPy/LGX\n"
+ "PzqlJIJ4h61s3UOroReHPB1keLZgpORqrvtpClOmABH9TLFRJA/WFg8Q2XYB/p0x\n"
+ "l/pWiaoBC+8wK9cDoMUK5yOwXeuCLffCb+UlAD0+z/qxJ2pisE8E9X8rRKRrWI+i\n"
+ "G7LtJCEn86EQK8KuRlJxKgj8lClZhoULB0oL4jbblBuNow9WRmM=\n"
+ "-----END CERTIFICATE-----\n";
+
+static char msg_pem[] =
+ "-----BEGIN PKCS7-----\n"
+ "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\n"
+ "-----END PKCS7-----\n";
+
+const gnutls_datum_t rca_datum = { (void *)rca_pem, sizeof(rca_pem) - 1 };
+const gnutls_datum_t ca_datum = { (void *)ca_pem, sizeof(ca_pem) - 1 };
+const gnutls_datum_t ee_datum = { (void *)ee_pem, sizeof(ee_pem) - 1 };
+const gnutls_datum_t msg_datum = { (void *)msg_pem, sizeof(msg_pem) - 1 };
+
+static void tls_log_func(int level, const char *str)
+{
+ fprintf(stderr, "%s |<%d>| %s", "err", level, str);
+}
+
+#define CHECK(X)\
+{\
+ r = X;\
+ if (r < 0)\
+ fail("error in %d: %s\n", __LINE__, gnutls_strerror(r));\
+}\
+
+void doit(void)
+{
+ int r;
+ gnutls_x509_crt_t rca_cert = NULL;
+ gnutls_x509_crt_t ca_cert = NULL;
+ gnutls_x509_crt_t ee_cert = NULL;
+ gnutls_x509_trust_list_t tlist = NULL;
+ gnutls_pkcs7_t pkcs7 = NULL;
+ gnutls_datum_t data = { (unsigned char *)"xxx", 3 };
+
+ if (debug) {
+ gnutls_global_set_log_function(tls_log_func);
+ gnutls_global_set_log_level(4711);
+ }
+
+ // Import certificates
+ CHECK(gnutls_x509_crt_init(&rca_cert));
+ CHECK(gnutls_x509_crt_import(rca_cert, &rca_datum, GNUTLS_X509_FMT_PEM));
+ CHECK(gnutls_x509_crt_init(&ca_cert));
+ CHECK(gnutls_x509_crt_import(ca_cert, &ca_datum, GNUTLS_X509_FMT_PEM));
+ CHECK(gnutls_x509_crt_init(&ee_cert));
+ CHECK(gnutls_x509_crt_import(ee_cert, &ee_datum, GNUTLS_X509_FMT_PEM));
+
+ // Setup trust store
+ CHECK(gnutls_x509_trust_list_init(&tlist, 0));
+ CHECK(gnutls_x509_trust_list_add_named_crt(tlist, rca_cert, "rca", 3, 0));
+ CHECK(gnutls_x509_trust_list_add_named_crt(tlist, ca_cert, "ca", 2, 0));
+ CHECK(gnutls_x509_trust_list_add_named_crt(tlist, ee_cert, "ee", 2, 0));
+
+ // Setup pkcs7 structure
+ CHECK(gnutls_pkcs7_init(&pkcs7));
+ CHECK(gnutls_pkcs7_import(pkcs7, &msg_datum, GNUTLS_X509_FMT_PEM));
+
+ // Signature verification
+ gnutls_pkcs7_verify(pkcs7, tlist, NULL, 0, 0, &data, 0);
+
+ gnutls_x509_crt_deinit(rca_cert);
+ gnutls_x509_crt_deinit(ca_cert);
+ gnutls_x509_crt_deinit(ee_cert);
+ gnutls_x509_trust_list_deinit(tlist, 0);
+ gnutls_pkcs7_deinit(pkcs7);
+}
--
2.37.2

View File

@ -1,242 +0,0 @@
From 9b50d94bf1c8e749d7dfc593c89e689a161444ae Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Mon, 26 Jun 2023 09:30:03 +0200
Subject: [PATCH] gnutls-3.6.16-rehandshake-tickets.patch
Signed-off-by: rpm-build <rpm-build>
---
lib/ext/session_ticket.c | 6 ++
lib/ext/session_ticket.h | 1 +
lib/libgnutls.map | 2 +
lib/state.c | 1 +
tests/Makefile.am | 3 +-
tests/tls12-rehandshake-ticket.c | 152 +++++++++++++++++++++++++++++++
6 files changed, 164 insertions(+), 1 deletion(-)
create mode 100644 tests/tls12-rehandshake-ticket.c
diff --git a/lib/ext/session_ticket.c b/lib/ext/session_ticket.c
index 8f22462..8d83a6c 100644
--- a/lib/ext/session_ticket.c
+++ b/lib/ext/session_ticket.c
@@ -618,6 +618,12 @@ gnutls_session_ticket_enable_server(gnutls_session_t session,
return 0;
}
+void
+_gnutls_session_ticket_disable_server(gnutls_session_t session)
+{
+ session->internals.flags |= GNUTLS_NO_TICKETS;
+}
+
/*
* Return zero if session tickets haven't been enabled.
*/
diff --git a/lib/ext/session_ticket.h b/lib/ext/session_ticket.h
index da804ec..660c9d3 100644
--- a/lib/ext/session_ticket.h
+++ b/lib/ext/session_ticket.h
@@ -36,5 +36,6 @@ int _gnutls_encrypt_session_ticket(gnutls_session_t session,
int _gnutls_decrypt_session_ticket(gnutls_session_t session,
const gnutls_datum_t *ticket_data,
gnutls_datum_t *state);
+void _gnutls_session_ticket_disable_server(gnutls_session_t session);
#endif /* GNUTLS_LIB_EXT_SESSION_TICKET_H */
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index d2f7c0a..6748b3a 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1432,4 +1432,6 @@ GNUTLS_PRIVATE_3_4 {
_gnutls_buffer_unescape;
_gnutls_buffer_pop_datum;
_gnutls_buffer_clear;
+ # needed by tests/tls12-rehandshake-cert-ticket
+ _gnutls_session_ticket_disable_server;
} GNUTLS_3_4;
diff --git a/lib/state.c b/lib/state.c
index 817a7b8..f1e9daa 100644
--- a/lib/state.c
+++ b/lib/state.c
@@ -452,6 +452,7 @@ void _gnutls_handshake_internal_state_clear(gnutls_session_t session)
session->internals.tfo.connect_addrlen = 0;
session->internals.tfo.connect_only = 0;
session->internals.early_data_received = 0;
+ session->internals.session_ticket_renew = 0;
}
/**
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0563d3c..7c5f5c4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -221,7 +221,8 @@ ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniquei
tls13-without-timeout-func buffer status-request-revoked \
set_x509_ocsp_multi_cli kdf-api keylog-func \
dtls_hello_random_value tls_hello_random_value x509cert-dntypes \
- pkcs7-verify-double-free
+ pkcs7-verify-double-free \
+ tls12-rehandshake-ticket
if HAVE_SECCOMP_TESTS
ctests += dtls-with-seccomp tls-with-seccomp dtls-client-with-seccomp tls-client-with-seccomp
diff --git a/tests/tls12-rehandshake-ticket.c b/tests/tls12-rehandshake-ticket.c
new file mode 100644
index 0000000..f96e46e
--- /dev/null
+++ b/tests/tls12-rehandshake-ticket.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * 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 <gnutls/gnutls.h>
+#include <assert.h>
+#include "cert-common.h"
+
+#include "utils.h"
+#include "eagain-common.h"
+
+const char *side = "";
+
+static void tls_log_func(int level, const char *str)
+{
+ fprintf(stderr, "%s|<%d>| %s", side, level, str);
+}
+
+#define MAX_BUF 1024
+
+void _gnutls_session_ticket_disable_server(gnutls_session_t session);
+
+static void run(void)
+{
+ char buffer[MAX_BUF + 1];
+ /* Server stuff. */
+ gnutls_certificate_credentials_t scred;
+ gnutls_session_t server;
+ gnutls_datum_t session_ticket_key = { NULL, 0 };
+ int sret;
+ /* Client stuff. */
+ gnutls_certificate_credentials_t ccred;
+ gnutls_session_t client;
+ int cret;
+
+ /* General init. */
+ global_init();
+ gnutls_global_set_log_function(tls_log_func);
+ if (debug)
+ gnutls_global_set_log_level(9);
+
+ /* Init server */
+ assert(gnutls_certificate_allocate_credentials(&scred) >= 0);
+ assert(gnutls_certificate_set_x509_key_mem(scred,
+ &server_ca3_localhost_cert,
+ &server_ca3_key,
+ GNUTLS_X509_FMT_PEM) >= 0);
+ assert(gnutls_certificate_set_x509_trust_mem(scred,
+ &ca3_cert,
+ GNUTLS_X509_FMT_PEM) >= 0);
+
+ assert(gnutls_init(&server, GNUTLS_SERVER) >= 0);
+ gnutls_certificate_server_set_request(server, GNUTLS_CERT_REQUEST);
+ assert(gnutls_priority_set_direct(server,
+ "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.1:+VERS-TLS1.2",
+ NULL) >= 0);
+
+ gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, scred);
+ gnutls_transport_set_push_function(server, server_push);
+ gnutls_transport_set_pull_function(server, server_pull);
+ gnutls_transport_set_ptr(server, server);
+
+ gnutls_session_ticket_key_generate(&session_ticket_key);
+ gnutls_session_ticket_enable_server(server, &session_ticket_key);
+
+ /* Init client */
+ assert(gnutls_certificate_allocate_credentials(&ccred) >= 0);
+ assert(gnutls_certificate_set_x509_key_mem
+ (ccred, &cli_ca3_cert_chain, &cli_ca3_key, GNUTLS_X509_FMT_PEM) >= 0);
+ assert(gnutls_certificate_set_x509_trust_mem
+ (ccred, &ca3_cert, GNUTLS_X509_FMT_PEM) >= 0);
+
+ gnutls_init(&client, GNUTLS_CLIENT);
+ assert(gnutls_priority_set_direct(client,
+ "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.1:+VERS-TLS1.2",
+ NULL) >= 0);
+
+ assert(gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, ccred) >= 0);
+
+ gnutls_transport_set_push_function(client, client_push);
+ gnutls_transport_set_pull_function(client, client_pull);
+ gnutls_transport_set_ptr(client, client);
+
+ HANDSHAKE(client, server);
+
+ /* Server initiates rehandshake */
+ switch_side("server");
+ sret = gnutls_rehandshake(server);
+ if (sret < 0) {
+ fail("Error sending %d byte packet: %s\n",
+ (int)sizeof(buffer), gnutls_strerror(sret));
+ } else if (debug)
+ success("server: starting rehandshake\n");
+
+ /* Stop sending session ticket */
+ _gnutls_session_ticket_disable_server(server);
+
+ /* Client gets notified with rehandshake */
+ switch_side("client");
+ do {
+ do {
+ cret = gnutls_record_recv(client, buffer, MAX_BUF);
+ } while (cret == GNUTLS_E_AGAIN || cret == GNUTLS_E_INTERRUPTED);
+ } while (cret > 0);
+
+ if (cret != GNUTLS_E_REHANDSHAKE) {
+ fail("client: Error receiving rehandshake: %s\n",
+ gnutls_strerror(cret));
+ }
+
+ HANDSHAKE(client, server);
+
+ gnutls_bye(client, GNUTLS_SHUT_WR);
+ gnutls_bye(server, GNUTLS_SHUT_WR);
+
+ gnutls_deinit(client);
+ gnutls_deinit(server);
+
+ gnutls_certificate_free_credentials(scred);
+ gnutls_certificate_free_credentials(ccred);
+
+ gnutls_free(session_ticket_key.data);
+
+ gnutls_global_deinit();
+ reset_buffers();
+}
+
+void doit(void)
+{
+ run();
+}
--
2.41.0

View File

@ -1,121 +0,0 @@
From fe912c5dba49dcecbd5c32bf8184e60a949af452 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Wed, 10 Jan 2024 19:13:17 +0900
Subject: [PATCH] rsa-psk: minimize branching after decryption
This moves any non-trivial code between gnutls_privkey_decrypt_data2
and the function return in _gnutls_proc_rsa_psk_client_kx up until the
decryption. This also avoids an extra memcpy to session->key.key.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/auth/rsa_psk.c | 68 ++++++++++++++++++++++++----------------------
1 file changed, 35 insertions(+), 33 deletions(-)
diff --git a/lib/auth/rsa_psk.c b/lib/auth/rsa_psk.c
index 93c2dc9998..8f3fe5a4bd 100644
--- a/lib/auth/rsa_psk.c
+++ b/lib/auth/rsa_psk.c
@@ -269,7 +269,6 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
int ret, dsize;
ssize_t data_size = _data_size;
gnutls_psk_server_credentials_t cred;
- gnutls_datum_t premaster_secret = { NULL, 0 };
volatile uint8_t ver_maj, ver_min;
cred = (gnutls_psk_server_credentials_t)
@@ -329,24 +328,48 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
ver_maj = _gnutls_get_adv_version_major(session);
ver_min = _gnutls_get_adv_version_minor(session);
- premaster_secret.data = gnutls_malloc(GNUTLS_MASTER_SIZE);
- if (premaster_secret.data == NULL) {
+ /* Find the key of this username. A random value will be
+ * filled in if the key is not found.
+ */
+ ret =
+ _gnutls_psk_pwd_find_entry(session, info->username, strlen(info->username), &pwd_psk);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ /* Allocate memory for premaster secret, and fill in the
+ * fields except the decryption result.
+ */
+ session->key.key.size = 2 + GNUTLS_MASTER_SIZE + 2 + pwd_psk.size;
+ session->key.key.data = gnutls_malloc(session->key.key.size);
+ if (session->key.key.data == NULL) {
gnutls_assert();
+ _gnutls_free_key_datum(&pwd_psk);
+ /* No need to zeroize, as the secret is not copied in yet */
+ _gnutls_free_datum(&session->key.key);
return GNUTLS_E_MEMORY_ERROR;
}
- premaster_secret.size = GNUTLS_MASTER_SIZE;
/* Fallback value when decryption fails. Needs to be unpredictable. */
- ret = gnutls_rnd(GNUTLS_RND_NONCE, premaster_secret.data,
- premaster_secret.size);
+ ret = gnutls_rnd(GNUTLS_RND_NONCE, session->key.key.data + 2,
+ GNUTLS_MASTER_SIZE);
if (ret < 0) {
gnutls_assert();
- goto cleanup;
+ _gnutls_free_key_datum(&pwd_psk);
+ /* No need to zeroize, as the secret is not copied in yet */
+ _gnutls_free_datum(&session->key.key);
+ return ret;
}
+ _gnutls_write_uint16(GNUTLS_MASTER_SIZE, session->key.key.data);
+ _gnutls_write_uint16(pwd_psk.size,
+ &session->key.key.data[2 + GNUTLS_MASTER_SIZE]);
+ memcpy(&session->key.key.data[2 + GNUTLS_MASTER_SIZE + 2],
+ pwd_psk.data, pwd_psk.size);
+ _gnutls_free_key_datum(&pwd_psk);
+
gnutls_privkey_decrypt_data2(session->internals.selected_key, 0,
- &ciphertext, premaster_secret.data,
- premaster_secret.size);
+ &ciphertext, session->key.key.data + 2,
+ GNUTLS_MASTER_SIZE);
/* After this point, any conditional on failure that cause differences
* in execution may create a timing or cache access pattern side
* channel that can be used as an oracle, so tread carefully */
@@ -365,31 +388,10 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
/* This is here to avoid the version check attack
* discussed above.
*/
- premaster_secret.data[0] = ver_maj;
- premaster_secret.data[1] = ver_min;
-
- /* find the key of this username
- */
- ret =
- _gnutls_psk_pwd_find_entry(session, info->username, strlen(info->username), &pwd_psk);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
-
- ret =
- set_rsa_psk_session_key(session, &pwd_psk, &premaster_secret);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
+ session->key.key.data[2] = ver_maj;
+ session->key.key.data[3] = ver_min;
- ret = 0;
- cleanup:
- _gnutls_free_key_datum(&pwd_psk);
- _gnutls_free_temp_key_datum(&premaster_secret);
-
- return ret;
+ return 0;
}
static int
--
2.43.0

View File

@ -1,202 +0,0 @@
From e007a54432c98618bde500649817d153225abf6b Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Thu, 7 Dec 2023 11:52:08 +0900
Subject: [PATCH] gnutls-3.6.16-rsa-psk-timing.patch
Signed-off-by: rpm-build <rpm-build>
---
lib/auth/rsa.c | 2 +-
lib/auth/rsa_psk.c | 93 +++++++++++++++++-----------------------------
lib/gnutls_int.h | 4 --
lib/priority.c | 1 -
4 files changed, 35 insertions(+), 65 deletions(-)
diff --git a/lib/auth/rsa.c b/lib/auth/rsa.c
index 858701f..02b6a34 100644
--- a/lib/auth/rsa.c
+++ b/lib/auth/rsa.c
@@ -207,7 +207,7 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data,
session->key.key.size);
/* After this point, any conditional on failure that cause differences
* in execution may create a timing or cache access pattern side
- * channel that can be used as an oracle, so treat very carefully */
+ * channel that can be used as an oracle, so tread carefully */
/* Error handling logic:
* In case decryption fails then don't inform the peer. Just use the
diff --git a/lib/auth/rsa_psk.c b/lib/auth/rsa_psk.c
index 1a9dab5..93c2dc9 100644
--- a/lib/auth/rsa_psk.c
+++ b/lib/auth/rsa_psk.c
@@ -264,14 +264,13 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
{
gnutls_datum_t username;
psk_auth_info_t info;
- gnutls_datum_t plaintext;
gnutls_datum_t ciphertext;
gnutls_datum_t pwd_psk = { NULL, 0 };
int ret, dsize;
- int randomize_key = 0;
ssize_t data_size = _data_size;
gnutls_psk_server_credentials_t cred;
gnutls_datum_t premaster_secret = { NULL, 0 };
+ volatile uint8_t ver_maj, ver_min;
cred = (gnutls_psk_server_credentials_t)
_gnutls_get_cred(session, GNUTLS_CRD_PSK);
@@ -327,71 +326,47 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
}
ciphertext.size = dsize;
- ret =
- gnutls_privkey_decrypt_data(session->internals.selected_key, 0,
- &ciphertext, &plaintext);
- if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE) {
- /* In case decryption fails then don't inform
- * the peer. Just use a random key. (in order to avoid
- * attack against pkcs-1 formatting).
- */
+ ver_maj = _gnutls_get_adv_version_major(session);
+ ver_min = _gnutls_get_adv_version_minor(session);
+
+ premaster_secret.data = gnutls_malloc(GNUTLS_MASTER_SIZE);
+ if (premaster_secret.data == NULL) {
gnutls_assert();
- _gnutls_debug_log
- ("auth_rsa_psk: Possible PKCS #1 format attack\n");
- if (ret >= 0) {
- gnutls_free(plaintext.data);
- }
- randomize_key = 1;
- } else {
- /* If the secret was properly formatted, then
- * check the version number.
- */
- if (_gnutls_get_adv_version_major(session) !=
- plaintext.data[0]
- || (session->internals.allow_wrong_pms == 0
- && _gnutls_get_adv_version_minor(session) !=
- plaintext.data[1])) {
- /* No error is returned here, if the version number check
- * fails. We proceed normally.
- * That is to defend against the attack described in the paper
- * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima,
- * Ondej Pokorny and Tomas Rosa.
- */
- gnutls_assert();
- _gnutls_debug_log
- ("auth_rsa: Possible PKCS #1 version check format attack\n");
- }
+ return GNUTLS_E_MEMORY_ERROR;
}
+ premaster_secret.size = GNUTLS_MASTER_SIZE;
-
- if (randomize_key != 0) {
- premaster_secret.size = GNUTLS_MASTER_SIZE;
- premaster_secret.data =
- gnutls_malloc(premaster_secret.size);
- if (premaster_secret.data == NULL) {
- gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- /* we do not need strong random numbers here.
- */
- ret = gnutls_rnd(GNUTLS_RND_NONCE, premaster_secret.data,
- premaster_secret.size);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
- } else {
- premaster_secret.data = plaintext.data;
- premaster_secret.size = plaintext.size;
+ /* Fallback value when decryption fails. Needs to be unpredictable. */
+ ret = gnutls_rnd(GNUTLS_RND_NONCE, premaster_secret.data,
+ premaster_secret.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
}
+ gnutls_privkey_decrypt_data2(session->internals.selected_key, 0,
+ &ciphertext, premaster_secret.data,
+ premaster_secret.size);
+ /* After this point, any conditional on failure that cause differences
+ * in execution may create a timing or cache access pattern side
+ * channel that can be used as an oracle, so tread carefully */
+
+ /* Error handling logic:
+ * In case decryption fails then don't inform the peer. Just use the
+ * random key previously generated. (in order to avoid attack against
+ * pkcs-1 formatting).
+ *
+ * If we get version mismatches no error is returned either. We
+ * proceed normally. This is to defend against the attack described
+ * in the paper "Attacking RSA-based sessions in SSL/TLS" by
+ * Vlastimil Klima, Ondej Pokorny and Tomas Rosa.
+ */
+
/* This is here to avoid the version check attack
* discussed above.
*/
-
- premaster_secret.data[0] = _gnutls_get_adv_version_major(session);
- premaster_secret.data[1] = _gnutls_get_adv_version_minor(session);
+ premaster_secret.data[0] = ver_maj;
+ premaster_secret.data[1] = ver_min;
/* find the key of this username
*/
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 31cec5c..815f69b 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -971,7 +971,6 @@ struct gnutls_priority_st {
bool _no_etm;
bool _no_ext_master_secret;
bool _allow_key_usage_violation;
- bool _allow_wrong_pms;
bool _dumbfw;
unsigned int _dh_prime_bits; /* old (deprecated) variable */
@@ -989,7 +988,6 @@ struct gnutls_priority_st {
(x)->no_etm = 1; \
(x)->no_ext_master_secret = 1; \
(x)->allow_key_usage_violation = 1; \
- (x)->allow_wrong_pms = 1; \
(x)->dumbfw = 1
#define ENABLE_PRIO_COMPAT(x) \
@@ -998,7 +996,6 @@ struct gnutls_priority_st {
(x)->_no_etm = 1; \
(x)->_no_ext_master_secret = 1; \
(x)->_allow_key_usage_violation = 1; \
- (x)->_allow_wrong_pms = 1; \
(x)->_dumbfw = 1
/* DH and RSA parameters types.
@@ -1123,7 +1120,6 @@ typedef struct {
bool no_etm;
bool no_ext_master_secret;
bool allow_key_usage_violation;
- bool allow_wrong_pms;
bool dumbfw;
/* old (deprecated) variable. This is used for both srp_prime_bits
diff --git a/lib/priority.c b/lib/priority.c
index 0a284ae..67ec887 100644
--- a/lib/priority.c
+++ b/lib/priority.c
@@ -681,7 +681,6 @@ gnutls_priority_set(gnutls_session_t session, gnutls_priority_t priority)
COPY_TO_INTERNALS(no_etm);
COPY_TO_INTERNALS(no_ext_master_secret);
COPY_TO_INTERNALS(allow_key_usage_violation);
- COPY_TO_INTERNALS(allow_wrong_pms);
COPY_TO_INTERNALS(dumbfw);
COPY_TO_INTERNALS(dh_prime_bits);
--
2.43.0

View File

@ -1,125 +0,0 @@
From 339bef12f478b3a12c59571c53645e31280baf7e Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Fri, 14 May 2021 15:59:37 +0200
Subject: [PATCH] cert auth: filter out unsupported cert types from TLS 1.2 CR
When the server is advertising signature algorithms in TLS 1.2
CertificateRequest, it shouldn't send certificate_types not backed by
any of those algorithms.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/auth/cert.c | 76 +++++++++++++++++++++++--
tests/suite/tls-fuzzer/gnutls-cert.json | 19 +++++++
2 files changed, 89 insertions(+), 6 deletions(-)
diff --git a/lib/auth/cert.c b/lib/auth/cert.c
index 3073a33d3..0b0f04b2b 100644
--- a/lib/auth/cert.c
+++ b/lib/auth/cert.c
@@ -64,6 +64,16 @@ typedef enum CertificateSigType { RSA_SIGN = 1, DSA_SIGN = 2, ECDSA_SIGN = 64,
#endif
} CertificateSigType;
+enum CertificateSigTypeFlags {
+ RSA_SIGN_FLAG = 1,
+ DSA_SIGN_FLAG = 1 << 1,
+ ECDSA_SIGN_FLAG = 1 << 2,
+#ifdef ENABLE_GOST
+ GOSTR34102012_256_SIGN_FLAG = 1 << 3,
+ GOSTR34102012_512_SIGN_FLAG = 1 << 4
+#endif
+};
+
/* Moves data from an internal certificate struct (gnutls_pcert_st) to
* another internal certificate struct (cert_auth_info_t), and deinitializes
* the former.
@@ -1281,6 +1291,7 @@ _gnutls_gen_cert_server_cert_req(gnutls_session_t session,
uint8_t tmp_data[CERTTYPE_SIZE];
const version_entry_st *ver = get_version(session);
unsigned init_pos = data->length;
+ enum CertificateSigTypeFlags flags;
if (unlikely(ver == NULL))
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
@@ -1297,18 +1308,71 @@ _gnutls_gen_cert_server_cert_req(gnutls_session_t session,
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
- i = 1;
+ if (_gnutls_version_has_selectable_sighash(ver)) {
+ size_t j;
+
+ flags = 0;
+ for (j = 0; j < session->internals.priorities->sigalg.size; j++) {
+ const gnutls_sign_entry_st *se =
+ session->internals.priorities->sigalg.entry[j];
+ switch (se->pk) {
+ case GNUTLS_PK_RSA:
+ case GNUTLS_PK_RSA_PSS:
+ flags |= RSA_SIGN_FLAG;
+ break;
+ case GNUTLS_PK_DSA:
+ flags |= DSA_SIGN_FLAG;
+ break;
+ case GNUTLS_PK_ECDSA:
+ flags |= ECDSA_SIGN_FLAG;
+ break;
#ifdef ENABLE_GOST
- if (_gnutls_kx_is_vko_gost(session->security_parameters.cs->kx_algorithm)) {
- tmp_data[i++] = GOSTR34102012_256_SIGN;
- tmp_data[i++] = GOSTR34102012_512_SIGN;
- } else
+ case GNUTLS_PK_GOST_12_256:
+ flags |= GOSTR34102012_256_SIGN_FLAG;
+ break;
+ case GNUTLS_PK_GOST_12_512:
+ flags |= GOSTR34102012_512_SIGN_FLAG;
+ break;
+#endif
+ default:
+ gnutls_assert();
+ _gnutls_debug_log(
+ "%s is unsupported for cert request\n",
+ gnutls_pk_get_name(se->pk));
+ }
+ }
+
+ } else {
+#ifdef ENABLE_GOST
+ if (_gnutls_kx_is_vko_gost(session->security_parameters.
+ cs->kx_algorithm)) {
+ flags = GOSTR34102012_256_SIGN_FLAG |
+ GOSTR34102012_512_SIGN_FLAG;
+ } else
#endif
- {
+ {
+ flags = RSA_SIGN_FLAG | DSA_SIGN_FLAG | ECDSA_SIGN_FLAG;
+ }
+ }
+
+ i = 1;
+ if (flags & RSA_SIGN_FLAG) {
tmp_data[i++] = RSA_SIGN;
+ }
+ if (flags & DSA_SIGN_FLAG) {
tmp_data[i++] = DSA_SIGN;
+ }
+ if (flags & ECDSA_SIGN_FLAG) {
tmp_data[i++] = ECDSA_SIGN;
}
+#ifdef ENABLE_GOST
+ if (flags & GOSTR34102012_256_SIGN_FLAG) {
+ tmp_data[i++] = GOSTR34102012_256_SIGN;
+ }
+ if (flags & GOSTR34102012_512_SIGN_FLAG) {
+ tmp_data[i++] = GOSTR34102012_512_SIGN;
+ }
+#endif
tmp_data[0] = i - 1;
ret = _gnutls_buffer_append_data(data, tmp_data, i);
--
2.31.1

View File

@ -1,283 +0,0 @@
From c2409e479df41620bceac314c76cabb1d35a4075 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Mon, 3 May 2021 16:35:43 +0200
Subject: [PATCH] x509/verify: treat SHA-1 signed CA in the trusted set
differently
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Suppose there is a certificate chain ending with an intermediate CA:
EE → ICA1 → ICA2. If the system trust store contains a root CA
generated with the same key as ICA2 but signed with a prohibited
algorithm, such as SHA-1, the library previously reported a
verification failure, though the situation is not uncommon during a
transition period of root CA.
This changes the library behavior such that the check on signature
algorithm will be skipped when examining the trusted root CA.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/x509/verify.c | 26 ++++---
tests/test-chains.h | 165 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 182 insertions(+), 9 deletions(-)
diff --git a/lib/x509/verify.c b/lib/x509/verify.c
index fd7c6a164..a50b5ea44 100644
--- a/lib/x509/verify.c
+++ b/lib/x509/verify.c
@@ -415,14 +415,19 @@ unsigned _gnutls_is_broken_sig_allowed(const gnutls_sign_entry_st *se, unsigned
#define CASE_SEC_PARAM(profile, level) \
case profile: \
sym_bits = gnutls_sec_param_to_symmetric_bits(level); \
- hash = gnutls_sign_get_hash_algorithm(sigalg); \
- entry = mac_to_entry(hash); \
- if (hash <= 0 || entry == NULL) { \
+ se = _gnutls_sign_to_entry(sigalg); \
+ if (unlikely(se == NULL)) { \
+ _gnutls_cert_log("cert", crt); \
+ _gnutls_debug_log(#level": certificate's signature algorithm is unknown\n"); \
+ return gnutls_assert_val(0); \
+ } \
+ if (unlikely(se->hash == GNUTLS_DIG_UNKNOWN)) { \
_gnutls_cert_log("cert", crt); \
_gnutls_debug_log(#level": certificate's signature hash is unknown\n"); \
return gnutls_assert_val(0); \
} \
- if (_gnutls_sign_get_hash_strength(sigalg) < sym_bits) { \
+ if (!trusted && \
+ _gnutls_sign_get_hash_strength(sigalg) < sym_bits) { \
_gnutls_cert_log("cert", crt); \
_gnutls_debug_log(#level": certificate's signature hash strength is unacceptable (is %u bits, needed %u)\n", _gnutls_sign_get_hash_strength(sigalg), sym_bits); \
return gnutls_assert_val(0); \
@@ -449,19 +454,22 @@ unsigned _gnutls_is_broken_sig_allowed(const gnutls_sign_entry_st *se, unsigned
* @crt: a certificate
* @issuer: the certificates issuer (allowed to be NULL)
* @sigalg: the signature algorithm used
+ * @trusted: whether @crt is treated as trusted (e.g., present in the system
+ * trust list); if it is true, the check on signature algorithm will
+ * be skipped
* @flags: the specified verification flags
*/
static unsigned is_level_acceptable(
gnutls_x509_crt_t crt, gnutls_x509_crt_t issuer,
- gnutls_sign_algorithm_t sigalg, unsigned flags)
+ gnutls_sign_algorithm_t sigalg, bool trusted,
+ unsigned flags)
{
gnutls_certificate_verification_profiles_t profile = GNUTLS_VFLAGS_TO_PROFILE(flags);
- const mac_entry_st *entry;
int issuer_pkalg = 0, pkalg, ret;
unsigned bits = 0, issuer_bits = 0, sym_bits = 0;
gnutls_pk_params_st params;
gnutls_sec_param_t sp;
- int hash;
+ const gnutls_sign_entry_st *se;
gnutls_certificate_verification_profiles_t min_profile;
min_profile = _gnutls_get_system_wide_verification_profile();
@@ -798,7 +806,7 @@ verify_crt(gnutls_x509_crt_t cert,
}
if (sigalg >= 0 && se) {
- if (is_level_acceptable(cert, issuer, sigalg, flags) == 0) {
+ if (is_level_acceptable(cert, issuer, sigalg, false, flags) == 0) {
MARK_INVALID(GNUTLS_CERT_INSECURE_ALGORITHM);
}
@@ -893,7 +901,7 @@ unsigned check_ca_sanity(const gnutls_x509_crt_t issuer,
/* we explicitly allow CAs which we do not support their self-algorithms
* to pass. */
- if (ret >= 0 && !is_level_acceptable(issuer, NULL, sigalg, flags)) {
+ if (ret >= 0 && !is_level_acceptable(issuer, NULL, sigalg, true, flags)) {
status |= GNUTLS_CERT_INSECURE_ALGORITHM|GNUTLS_CERT_INVALID;
}
diff --git a/tests/test-chains.h b/tests/test-chains.h
index 9b06b85f5..64f50fabf 100644
--- a/tests/test-chains.h
+++ b/tests/test-chains.h
@@ -4106,6 +4106,163 @@ static const char *superseding_ca[] = {
NULL
};
+static const char *rsa_sha1_in_trusted[] = {
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIID0jCCAoqgAwIBAgIUezaBB7f4TW75oc3UV57oJvXmbBYwDQYJKoZIhvcNAQEL\n"
+ "BQAwGTEXMBUGA1UEAxMOR251VExTIHRlc3QgQ0EwHhcNMjEwNTAzMTQyNzIxWhcN\n"
+ "MjIwNTAzMTQyNzIxWjA3MRgwFgYDVQQDEw90ZXN0LmdudXRscy5vcmcxGzAZBgNV\n"
+ "BAoTEkdudVRMUyB0ZXN0IHNlcnZlcjCCAVIwDQYJKoZIhvcNAQEBBQADggE/ADCC\n"
+ "AToCggExALRrJ5glr8H/HsqwfvTYvO1DhmdUXdq0HsKQX4M8AhH8E3KFsoikZUEL\n"
+ "dl8jvoqf/nlLczsux0s8vxbJl1U1F/OhckswwuAnlBLzVgDmzoJLEV2kHpv6+rkb\n"
+ "Kk0Ytbql5gzHqKihbaqIhNyWDrJsHDWq58eUPfnVx8KiDUuzbnr3CF/FCc0Vkxr3\n"
+ "mN8qTGaJJO0f0BZjgWWlWDuhzSVim5mBVAgXGOx8LwiiOyhXMp0XRwqG+2KxQZnm\n"
+ "+96o6iB+8xvuuuqaIWQpkvKtc+UZBZ03U+IRnxhfIrriiw0AjJ4vp4c9QL5KoqWS\n"
+ "CAwuYcBYfJqZ4dasgzklzz4b7eujbZ3LxTjewcdumzQUvjA+gpAeuUqaduTvMwxG\n"
+ "ojFy9sNhC/iqZ4n0peV2N6Epn4B5qnUCAwEAAaOBkzCBkDAMBgNVHRMBAf8EAjAA\n"
+ "MBoGA1UdEQQTMBGCD3Rlc3QuZ251dGxzLm9yZzATBgNVHSUEDDAKBggrBgEFBQcD\n"
+ "ATAPBgNVHQ8BAf8EBQMDB6AAMB0GA1UdDgQWBBRIIzRTCokxOEpa6sq20qbezh0r\n"
+ "GDAfBgNVHSMEGDAWgBQedyNtZzEfkQebli/s/MhG/ozhAzANBgkqhkiG9w0BAQsF\n"
+ "AAOCATEAXs8lOV231HQerhSGEjZJz0vBuA3biKYlu3cwCTKvF6EOyYMSWOnfqqD0\n"
+ "eDhpo1pzGtUa2zYLHagb+sU2NSTe0sqP+PK1giUg8X8/tRtWKk1p/m76yK/3iaty\n"
+ "flgz+eMai4xQu2FvAJzIASFjM9R+Pgpcf/zdvkiUPv8Rdm9FieyAZnJSo9hJHLxN\n"
+ "x60tfC5yyswdbGGW0GbJ2kr+xMfVZvxgO/x6AXlOaUGQ+jZAu9eJwFQMDW5h5/S1\n"
+ "PJkIt7f7jkU33cG+BawcjhT0GzxuvDnnCG0L7/z7bR+Sw2kNKqHbHorzv91R20Oh\n"
+ "CIISJPkiiP+mYcglTp1d9gw09GwSkGbldb9ibfc0hKyxiImFfIiTqDbXJcpKH98o\n"
+ "W8hWkb20QURlY+QM5MD49znfhPKMTQ==\n"
+ "-----END CERTIFICATE-----\n",
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIID2TCCAkGgAwIBAgIUWsb4DATcefXbo0WrBfgqVMvPGawwDQYJKoZIhvcNAQEL\n"
+ "BQAwHjEcMBoGA1UEAxMTR251VExTIHRlc3Qgcm9vdCBDQTAeFw0yMTA1MDMxNDI2\n"
+ "MzVaFw0yMjA1MDMxNDI2MzVaMBkxFzAVBgNVBAMTDkdudVRMUyB0ZXN0IENBMIIB\n"
+ "UjANBgkqhkiG9w0BAQEFAAOCAT8AMIIBOgKCATEAnORCsX1unl//fy2d1054XduI\n"
+ "g/3CqVBaT3Hca65SEoDwh0KiPtQoOgZLdKY2cobGs/ojYtOjcs0KnlPYdmtjEh6W\n"
+ "EhuJU95v4TQdC4OLMiE56eIGq252hZAbHoTL84Q14DxQWGuzQK830iml7fbw2WcI\n"
+ "cRQ8vFGs8SzfXw63+MI6Fq6iMAQIqP08WzGmRRzL5wvCiPhCVkrPmwbXoABub6AA\n"
+ "sYwWPJB91M9/lx5gFH5k9/iPfi3s2Kg3F8MOcppqFYjxDSnsfiz6eMh1+bYVIAo3\n"
+ "67vGVYHigXMEZC2FezlwIHaZzpEoFlY3a7LFJ00yrjQ910r8UE+CEMTYzE40D0ol\n"
+ "CMo7FA9RCjeO3bUIoYaIdVTUGWEGHWSeoxGei9Gkm6u+ASj8f+i0jxdD2qXsewID\n"
+ "AQABo2QwYjAPBgNVHRMBAf8EBTADAQH/MA8GA1UdDwEB/wQFAwMHBAAwHQYDVR0O\n"
+ "BBYEFB53I21nMR+RB5uWL+z8yEb+jOEDMB8GA1UdIwQYMBaAFCApU0Q1pxZL+AW3\n"
+ "GctysPWxl+SfMA0GCSqGSIb3DQEBCwUAA4IBgQBbboeDr/rLT1tZWrdHq8FvflGm\n"
+ "EpxZIRU4DdDD/SUCWSPQvjBq0MvuKxs5FfJCKrDf2kS2qlZ1rO0AuWwREoDeTOEc\n"
+ "arjFoCry+JQ+USqS5F4gsp4XlYvli27iMp3dlnhFXEQQy7/y+gM5c9wnMi8v/LUz\n"
+ "AV6QHX0fkb4XeazeJ+Nq0EkjqiYxylN6mP+5LAEMBG/wGviAoviQ5tN9zdoQs/nT\n"
+ "3jTw3cOauuPjdcOTfo71+/MtBzhPchgNIyQo4aB40XVWsLAoruL/3CFFlTniihtd\n"
+ "zA2zA7JvbuuKx6BOv2IbWOUweb732ZpYbDgEcXp/6Cj/SIUGxidpEgdCJGqyqdC7\n"
+ "b58ujxclC6QTcicw+SX5LBox8WGLfj+x+V3uVBz9+EK608xphTj4kLh9peII9v3n\n"
+ "vBUoZRTiUTCvH4AJJgAfa3mYrSxzueuqBOwXcvZ+8OJ0J1CP21pmK5nxR7f1nm9Q\n"
+ "sYA1VHfC2dtyAYlByeF5iHl5hFR6vy1jJyzxg2M=\n"
+ "-----END CERTIFICATE-----\n",
+ NULL
+};
+
+static const char *rsa_sha1_in_trusted_ca[] = {
+ /* This CA is generated with the same key as rsa_sha1_in_trusted[1], but
+ * self-signed using SHA-1.
+ */
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDYzCCAhugAwIBAgIUahO8CvYPHTAltKCC2rAIcXUiLlAwDQYJKoZIhvcNAQEF\n"
+ "BQAwGTEXMBUGA1UEAxMOR251VExTIHRlc3QgQ0EwHhcNMjEwNTAzMTQyMDM1WhcN\n"
+ "MjIwNTAzMTQyMDM1WjAZMRcwFQYDVQQDEw5HbnVUTFMgdGVzdCBDQTCCAVIwDQYJ\n"
+ "KoZIhvcNAQEBBQADggE/ADCCAToCggExAJzkQrF9bp5f/38tnddOeF3biIP9wqlQ\n"
+ "Wk9x3GuuUhKA8IdCoj7UKDoGS3SmNnKGxrP6I2LTo3LNCp5T2HZrYxIelhIbiVPe\n"
+ "b+E0HQuDizIhOeniBqtudoWQGx6Ey/OENeA8UFhrs0CvN9Ippe328NlnCHEUPLxR\n"
+ "rPEs318Ot/jCOhauojAECKj9PFsxpkUcy+cLwoj4QlZKz5sG16AAbm+gALGMFjyQ\n"
+ "fdTPf5ceYBR+ZPf4j34t7NioNxfDDnKaahWI8Q0p7H4s+njIdfm2FSAKN+u7xlWB\n"
+ "4oFzBGQthXs5cCB2mc6RKBZWN2uyxSdNMq40PddK/FBPghDE2MxONA9KJQjKOxQP\n"
+ "UQo3jt21CKGGiHVU1BlhBh1knqMRnovRpJurvgEo/H/otI8XQ9ql7HsCAwEAAaND\n"
+ "MEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwQAMB0GA1UdDgQWBBQe\n"
+ "dyNtZzEfkQebli/s/MhG/ozhAzANBgkqhkiG9w0BAQUFAAOCATEAYLm/4DfUp+mA\n"
+ "S/23a2bwybJoPCMzKZpi+veXkqoq/a/BCUkFpqnjpVjz0ujVKK121oeOPBAa/mG1\n"
+ "Y3fJYP+b3PloL/6xj/8680TveGirCr0Rp/8XWa8lt+Ge8DM3mfTGWFTWHa0lD9VK\n"
+ "gjV1oNZNLe5SKA6dJLAp/NjCxc/vuOkThQPeaoO5Iy/Z6m7CpTLO7T4syJFtDmSn\n"
+ "Pa/yFUDTgJYFlGVM+KC1r8bhZ6Ao1CAXTcT5Lcbe/aCcyk6B3J2AnYsqPMVNEVhb\n"
+ "9eMGO/WG24hMLy6eb1r/yL8uQ/uGi2rRlNJN8GTg09YR7l5fHrHxuHc/sme0jsnJ\n"
+ "wtqGLCJsrh7Ae1fKVUueO00Yx9BGuzLswMvnT5f0oYs0jrXgMrTbIWS/DjOcYIHb\n"
+ "w3SV1ZRcNg==\n"
+ "-----END CERTIFICATE-----\n",
+ NULL
+};
+
+static const char *rsa_sha1_not_in_trusted[] = {
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIID0jCCAoqgAwIBAgIUNCvPV9OvyuVMtnkC3ZAvh959h4MwDQYJKoZIhvcNAQEL\n"
+ "BQAwGTEXMBUGA1UEAxMOR251VExTIHRlc3QgQ0EwHhcNMjEwNTA0MDg0NzAzWhcN\n"
+ "MjIwNTA0MDg0NzAzWjA3MRgwFgYDVQQDEw90ZXN0LmdudXRscy5vcmcxGzAZBgNV\n"
+ "BAoTEkdudVRMUyB0ZXN0IHNlcnZlcjCCAVIwDQYJKoZIhvcNAQEBBQADggE/ADCC\n"
+ "AToCggExALRrJ5glr8H/HsqwfvTYvO1DhmdUXdq0HsKQX4M8AhH8E3KFsoikZUEL\n"
+ "dl8jvoqf/nlLczsux0s8vxbJl1U1F/OhckswwuAnlBLzVgDmzoJLEV2kHpv6+rkb\n"
+ "Kk0Ytbql5gzHqKihbaqIhNyWDrJsHDWq58eUPfnVx8KiDUuzbnr3CF/FCc0Vkxr3\n"
+ "mN8qTGaJJO0f0BZjgWWlWDuhzSVim5mBVAgXGOx8LwiiOyhXMp0XRwqG+2KxQZnm\n"
+ "+96o6iB+8xvuuuqaIWQpkvKtc+UZBZ03U+IRnxhfIrriiw0AjJ4vp4c9QL5KoqWS\n"
+ "CAwuYcBYfJqZ4dasgzklzz4b7eujbZ3LxTjewcdumzQUvjA+gpAeuUqaduTvMwxG\n"
+ "ojFy9sNhC/iqZ4n0peV2N6Epn4B5qnUCAwEAAaOBkzCBkDAMBgNVHRMBAf8EAjAA\n"
+ "MBoGA1UdEQQTMBGCD3Rlc3QuZ251dGxzLm9yZzATBgNVHSUEDDAKBggrBgEFBQcD\n"
+ "ATAPBgNVHQ8BAf8EBQMDB6AAMB0GA1UdDgQWBBRIIzRTCokxOEpa6sq20qbezh0r\n"
+ "GDAfBgNVHSMEGDAWgBQedyNtZzEfkQebli/s/MhG/ozhAzANBgkqhkiG9w0BAQsF\n"
+ "AAOCATEAWs/Qa1Ebydwo4Ke2KEdy5cUTSZjnoz93XpbrP9W60MJ4d2DIQPcYUcLF\n"
+ "+glez+mRtVXDRtH5V/4yZX1EdgrPVQGeVlO5HbNiYyYw/Yj3H6kzWtUbBxdOAOE/\n"
+ "/ul8RCKKMfvYBHCBgjBMW0aFm31Q1Z8m8nanBusyJ0DG1scBHu4/3vTCZthZAxc5\n"
+ "3l3t/jjsNRS+k5t6Ay8nEY1tAZSGVqN8qufzO2NBO06sQagp09FTfDh581OBcVtF\n"
+ "X7O0cffAWHk3JoywzEWFEAhVPqFlk07wG2O+k+fYZfavsJko5q+yWkxu8RDh4wAx\n"
+ "7UzKudGOQ+NhfYJ7N7V1/RFg1z75gE3GTUX7qmGZEVDOsMyiuUeYg8znyYpBV55Q\n"
+ "4BNr0ukwmwOdvUf+ksCu6PdOGaqThA==\n"
+ "-----END CERTIFICATE-----\n",
+ /* ICA with SHA1 signature */
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIID2TCCAkGgAwIBAgIUYaKJkQft87M1TF+Jd30py3yIq4swDQYJKoZIhvcNAQEF\n"
+ "BQAwHjEcMBoGA1UEAxMTR251VExTIHRlc3Qgcm9vdCBDQTAeFw0yMTA1MDQwODQ1\n"
+ "NDdaFw0yMjA1MDQwODQ1NDdaMBkxFzAVBgNVBAMTDkdudVRMUyB0ZXN0IENBMIIB\n"
+ "UjANBgkqhkiG9w0BAQEFAAOCAT8AMIIBOgKCATEAnORCsX1unl//fy2d1054XduI\n"
+ "g/3CqVBaT3Hca65SEoDwh0KiPtQoOgZLdKY2cobGs/ojYtOjcs0KnlPYdmtjEh6W\n"
+ "EhuJU95v4TQdC4OLMiE56eIGq252hZAbHoTL84Q14DxQWGuzQK830iml7fbw2WcI\n"
+ "cRQ8vFGs8SzfXw63+MI6Fq6iMAQIqP08WzGmRRzL5wvCiPhCVkrPmwbXoABub6AA\n"
+ "sYwWPJB91M9/lx5gFH5k9/iPfi3s2Kg3F8MOcppqFYjxDSnsfiz6eMh1+bYVIAo3\n"
+ "67vGVYHigXMEZC2FezlwIHaZzpEoFlY3a7LFJ00yrjQ910r8UE+CEMTYzE40D0ol\n"
+ "CMo7FA9RCjeO3bUIoYaIdVTUGWEGHWSeoxGei9Gkm6u+ASj8f+i0jxdD2qXsewID\n"
+ "AQABo2QwYjAPBgNVHRMBAf8EBTADAQH/MA8GA1UdDwEB/wQFAwMHBAAwHQYDVR0O\n"
+ "BBYEFB53I21nMR+RB5uWL+z8yEb+jOEDMB8GA1UdIwQYMBaAFCApU0Q1pxZL+AW3\n"
+ "GctysPWxl+SfMA0GCSqGSIb3DQEBBQUAA4IBgQAewBcAGUGX28I5PDtuJkxoHonD\n"
+ "muHdXpYnrz1YXN4b7odNXockz++Xovgj126fo+PeWgmaaCic98ZcGnyVTi9+3oqN\n"
+ "2Bf4NNfyzSccgZZTphzbwjMcnc983HLQgsLSAOVivPHj5GEN58EWWamc9yA0VjGn\n"
+ "cuYmFN2dlFA8/ClEbVGu3UXBe6OljR5zUr+6oiSp2J+Rl7SerVSHlst07iU2tkeB\n"
+ "dlfOD5CquUGSka3SKvEfvu5SwYrCQVfYB6eMLInm7A0/ca0Jn3Oh4fMf2rIg/E3K\n"
+ "qsopxsu8BXrLoGK4MxbxPA65JpczhZgilQQi3e3RIvxrvyD2qamjaNbyG5cr8mW4\n"
+ "VOLf3vUORbkTi5sE7uRMu2B3z3N7ajsuQM8RHB17hOCB2FO/8rermq/oeJNtx57L\n"
+ "5s5NxCHYTksQ4gkpR4gfTIO/zwXJSwGa/Zi2y2wIi/1qr7lppBsKV2rDWX7QiIeA\n"
+ "PxOxyJA2eSeqCorz9vk3aHXleSpxsWGgKiJVmV0=\n"
+ "-----END CERTIFICATE-----\n",
+ NULL
+};
+
+static const char *rsa_sha1_not_in_trusted_ca[] = {
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIEDTCCAnWgAwIBAgIUd5X8NZput+aNPEd9h92r4KAu16MwDQYJKoZIhvcNAQEL\n"
+ "BQAwHjEcMBoGA1UEAxMTR251VExTIHRlc3Qgcm9vdCBDQTAeFw0yMTA1MDMxNDI1\n"
+ "MDNaFw0yMjA1MDMxNDI1MDNaMB4xHDAaBgNVBAMTE0dudVRMUyB0ZXN0IHJvb3Qg\n"
+ "Q0EwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCsFAaMb/iRN+OFqQNh\n"
+ "OkkXGZlb+eLerLuB9ELnYwyLIh4MTXh0RjFZdCQLsQHfY/YFv0C50rmoXTA/d3Ef\n"
+ "K/P243KjX0XBWjO9TBuN0zth50eq94zf69yxA/a+kmT+O5YLfhi2ELM5F3IjOUoZ\n"
+ "lL0IGlFJwauAkaNylp/Evd5nW7g5DUJvMm4A3RXNfZt9gAD4lPRwryQq9jxT48Xu\n"
+ "fB0kAPEG/l/Izbz2rYin5+nySL+a0CSNuEbITxidtMhveB747oR0QS2sMQKji1ur\n"
+ "pRJ945SHiYJIgVuFAJc9StikSyIrxZgK45kAzcQAyRWWKiMNH5PprGFYJp+ypwhm\n"
+ "1t8Bphj2RFJAG3XRRZF/9uJIYc5mEHCsZFZ/IFRaKqyN30kAUijgNt+lW5mZXVFU\n"
+ "aqzV2zHjSG8jsGdia3cfBP46Z1q2eAh5jOCucTq1F7qZdVhOFmP9jFE6Uy5Kbwgc\n"
+ "kNAnsEllQeJQL2odVa7woKkZZ4M/c72X5tpBU38Rs3krn3sCAwEAAaNDMEEwDwYD\n"
+ "VR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwQAMB0GA1UdDgQWBBQgKVNENacW\n"
+ "S/gFtxnLcrD1sZfknzANBgkqhkiG9w0BAQsFAAOCAYEAaZMV71mZ9FYoVdpho61h\n"
+ "WWPs5GppQLJ1w70DNtGZ+lFrk/KopeDvOu1i61QLWRzcZCZMl+npiX1KH5kjVo3v\n"
+ "C9G8kdMW6EVRk5p6qCJMPFN2U+grMMp50aY5kmw+/v+Lhk5T/VG93l63P91FkUre\n"
+ "o8qhOudJExoUnR1uB9M6HMAxVn8Lm/N1LGPiP6A6Pboo716H7mg/A7pv9zoZ6jUp\n"
+ "7x693mA/b3I/QpDx/nJcmcdqxgEuW+aRlFXgnYZRFAawxi+5M9EwCWbkSTO4OMHP\n"
+ "Qlvak3tJO+wb92b0cICOOtzIPgQ+caiLg9d0FvesALmQzDmNmtqynoO85+Ia2Ywh\n"
+ "nxKPlpeImhLN9nGl9sOeW2m4mnA5r0h1vgML4v/MWL4TQhXallc31uFNj5HyFaTh\n"
+ "6Mr0g3GeQgN0jpT+aIOiKuW9fLts54+Ntj1NN40slqi3Y+/Yd6xhj+NgmbRvybZu\n"
+ "tnYFXKC0Q+QUf38horqG2Mc3/uh8MOm0eYUXwGJOdXYD\n"
+ "-----END CERTIFICATE-----\n",
+ NULL
+};
+
#if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-variable"
@@ -4275,6 +4432,14 @@ static struct
{ "ed448 - ok", ed448, &ed448[0], GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_ULTRA),
0, NULL, 1584352960, 1},
{ "superseding - ok", superseding, superseding_ca, 0, 0, 0, 1590928011 },
+ { "rsa-sha1 in trusted - ok",
+ rsa_sha1_in_trusted, rsa_sha1_in_trusted_ca,
+ GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_MEDIUM),
+ 0, NULL, 1620052390, 1},
+ { "rsa-sha1 not in trusted - not ok",
+ rsa_sha1_not_in_trusted, rsa_sha1_not_in_trusted_ca,
+ GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_MEDIUM),
+ GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID, NULL, 1620118136, 1},
{ NULL, NULL, NULL, 0, 0}
};
--
2.31.1

View File

@ -1,13 +0,0 @@
diff --git a/guile/src/Makefile.in b/guile/src/Makefile.in
index 95e1e9c..1dfc88e 100644
--- a/guile/src/Makefile.in
+++ b/guile/src/Makefile.in
@@ -1483,7 +1483,7 @@ guileextension_LTLIBRARIES = guile-gnutls-v-2.la
# Use '-module' to build a "dlopenable module", in Libtool terms.
# Use '-undefined' to placate Libtool on Windows; see
# <https://lists.gnutls.org/pipermail/gnutls-devel/2014-December/007294.html>.
-guile_gnutls_v_2_la_LDFLAGS = -module -no-undefined
+guile_gnutls_v_2_la_LDFLAGS = -module -no-undefined -Wl,-z,lazy
# Linking against GnuTLS.
GNUTLS_CORE_LIBS = $(top_builddir)/lib/libgnutls.la

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
From c7f4ce40eaecafdefbf4db0ac2d3665bc0c41b33 Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Tue, 21 Nov 2023 14:13:38 +0900
Subject: [PATCH] gnutls-3.7.2-no-explicit-init.patch
Signed-off-by: rpm-build <rpm-build>
---
lib/global.c | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/lib/global.c b/lib/global.c
index 924ec94..3baa202 100644
--- a/lib/global.c
+++ b/lib/global.c
@@ -510,15 +510,6 @@ static void _CONSTRUCTOR lib_init(void)
return;
}
- e = secure_getenv("GNUTLS_NO_EXPLICIT_INIT");
- if (e != NULL) {
- _gnutls_debug_log(
- "GNUTLS_NO_EXPLICIT_INIT is deprecated; use GNUTLS_NO_IMPLICIT_INIT\n");
- ret = atoi(e);
- if (ret == 1)
- return;
- }
-
ret = _gnutls_global_init(1);
if (ret < 0) {
fprintf(stderr, "Error in GnuTLS initialization: %s\n",
--
2.41.0

View File

@ -0,0 +1,26 @@
diff --git a/lib/priority.c b/lib/priority.c
index 9feec47fe2..40511710fd 100644
--- a/lib/priority.c
+++ b/lib/priority.c
@@ -2001,13 +2001,14 @@ char *_gnutls_resolve_priorities(const char* priorities)
additional++;
}
- /* Always try to refresh the cached data, to allow it to be
- * updated without restarting all applications.
- */
- ret = _gnutls_update_system_priorities(false /* defer_system_wide */);
- if (ret < 0) {
- _gnutls_debug_log("failed to update system priorities: %s\n",
- gnutls_strerror(ret));
+ /* If priority string is not constructed yet, construct and finalize */
+ if (!system_wide_config.priority_string) {
+ ret = _gnutls_update_system_priorities(false
+ /* defer_system_wide */);
+ if (ret < 0) {
+ _gnutls_debug_log("failed to update system priorities: "
+ " %s\n", gnutls_strerror(ret));
+ }
}
do {

View File

@ -0,0 +1,41 @@
From 968de8a9779788a853a4c0cd75beda779cb15f52 Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Thu, 16 Nov 2023 17:09:58 +0900
Subject: [PATCH] gnutls-3.7.6-drbg-reseed.patch
Signed-off-by: rpm-build <rpm-build>
---
lib/nettle/sysrng-linux.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/lib/nettle/sysrng-linux.c b/lib/nettle/sysrng-linux.c
index 25d74fe..8b9cc46 100644
--- a/lib/nettle/sysrng-linux.c
+++ b/lib/nettle/sysrng-linux.c
@@ -31,6 +31,9 @@
#include "num.h"
#include <errno.h>
#include "rnd-common.h"
+#include "fips.h"
+#else
+#define _gnutls_fips_mode_enabled() 0
#endif
#include <sys/types.h>
@@ -104,7 +107,12 @@ static int force_getrandom(void *buf, size_t buflen, unsigned int flags)
static int _rnd_get_system_entropy_getrandom(void *_rnd, size_t size)
{
int ret;
- ret = force_getrandom(_rnd, size, 0);
+ unsigned int flags = 0;
+
+ if (_gnutls_fips_mode_enabled()) {
+ flags |= 2/*GRND_RANDOM*/;
+ }
+ ret = force_getrandom(_rnd, size, flags);
if (ret == -1) {
int e = errno;
gnutls_assert();
--
2.41.0

View File

@ -1,114 +0,0 @@
From c149dd0767f32789e391280cb1eb06b7eb7c6bce Mon Sep 17 00:00:00 2001
From: Alexander Sosedkin <asosedkin@redhat.com>
Date: Tue, 9 Aug 2022 16:05:53 +0200
Subject: [PATCH 1/2] auth/rsa: side-step potential side-channel
Remove branching that depends on secret data.
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
Signed-off-by: Hubert Kario <hkario@redhat.com>
Tested-by: Hubert Kario <hkario@redhat.com>
---
lib/auth/rsa.c | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/lib/auth/rsa.c b/lib/auth/rsa.c
index 8108ee841d..6b158bacb2 100644
--- a/lib/auth/rsa.c
+++ b/lib/auth/rsa.c
@@ -155,7 +155,6 @@ static int
proc_rsa_client_kx(gnutls_session_t session, uint8_t * data,
size_t _data_size)
{
- const char attack_error[] = "auth_rsa: Possible PKCS #1 attack\n";
gnutls_datum_t ciphertext;
int ret, dsize;
ssize_t data_size = _data_size;
@@ -235,15 +234,6 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data,
ok &= CONSTCHECK_NOT_EQUAL(check_ver_min, 0) &
CONSTCHECK_EQUAL(session->key.key.data[1], ver_min);
- if (ok) {
- /* call logging function unconditionally so all branches are
- * indistinguishable for timing and cache access when debug
- * logging is disabled */
- _gnutls_no_log("%s", attack_error);
- } else {
- _gnutls_debug_log("%s", attack_error);
- }
-
/* This is here to avoid the version check attack
* discussed above.
*/
--
2.39.1
From 7c963102ec2119eecc1789b993aabe5edfd75f3b Mon Sep 17 00:00:00 2001
From: Hubert Kario <hkario@redhat.com>
Date: Wed, 8 Feb 2023 14:32:09 +0100
Subject: [PATCH 2/2] rsa: remove dead code
since the `ok` variable isn't used any more, we can remove all code
used to calculate it
Signed-off-by: Hubert Kario <hkario@redhat.com>
---
lib/auth/rsa.c | 20 +++-----------------
1 file changed, 3 insertions(+), 17 deletions(-)
diff --git a/lib/auth/rsa.c b/lib/auth/rsa.c
index 6b158bacb2..858701fe6e 100644
--- a/lib/auth/rsa.c
+++ b/lib/auth/rsa.c
@@ -159,8 +159,6 @@ 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;
- volatile uint8_t check_ver_min;
- volatile uint32_t ok;
#ifdef ENABLE_SSL3
if (get_num_version(session) == GNUTLS_SSL3) {
@@ -186,7 +184,6 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data,
ver_maj = _gnutls_get_adv_version_major(session);
ver_min = _gnutls_get_adv_version_minor(session);
- check_ver_min = (session->internals.allow_wrong_pms == 0);
session->key.key.data = gnutls_malloc(GNUTLS_MASTER_SIZE);
if (session->key.key.data == NULL) {
@@ -205,10 +202,9 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data,
return ret;
}
- ret =
- gnutls_privkey_decrypt_data2(session->internals.selected_key,
- 0, &ciphertext, session->key.key.data,
- session->key.key.size);
+ gnutls_privkey_decrypt_data2(session->internals.selected_key,
+ 0, &ciphertext, session->key.key.data,
+ session->key.key.size);
/* After this point, any conditional on failure that cause differences
* in execution may create a timing or cache access pattern side
* channel that can be used as an oracle, so treat very carefully */
@@ -224,16 +220,6 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data,
* Vlastimil Klima, Ondej Pokorny and Tomas Rosa.
*/
- /* ok is 0 in case of error and 1 in case of success. */
-
- /* if ret < 0 */
- ok = CONSTCHECK_EQUAL(ret, 0);
- /* session->key.key.data[0] must equal ver_maj */
- ok &= CONSTCHECK_EQUAL(session->key.key.data[0], ver_maj);
- /* if check_ver_min then session->key.key.data[1] must equal ver_min */
- ok &= CONSTCHECK_NOT_EQUAL(check_ver_min, 0) &
- CONSTCHECK_EQUAL(session->key.key.data[1], ver_min);
-
/* This is here to avoid the version check attack
* discussed above.
*/
--
2.39.1

View File

@ -1,4 +1,4 @@
From 08f979a318f8c553b4b781e0a586ba54f4e7b165 Mon Sep 17 00:00:00 2001
From f23de850c8f37bd498bbdb1adc491ee05614ca11 Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Fri, 6 Feb 2026 15:43:54 +0100
Subject: [PATCH 1/2] tests/pkcs11/pkcs11-mock4: add, modified for 3.8.10
@ -10,12 +10,12 @@ Subject: [PATCH 1/2] tests/pkcs11/pkcs11-mock4: add, modified for 3.8.10
create mode 100644 tests/pkcs11/pkcs11-mock4.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 1019f6c1d8..467284925a 100644
index 9e5c7de84..62c4ec2f9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -338,6 +338,11 @@ libpkcs11mock2_la_SOURCES = pkcs11/pkcs11-mock2.c
libpkcs11mock2_la_LDFLAGS = -shared -rpath $(pkglibdir) -module -no-undefined -avoid-version
libpkcs11mock2_la_LIBADD = ../gl/libgnu.la
@@ -358,6 +358,11 @@ libpkcs11mock3_la_SOURCES = pkcs11/pkcs11-mock3.c
libpkcs11mock3_la_LDFLAGS = -shared -rpath $(pkglibdir) -module -no-undefined -avoid-version
libpkcs11mock3_la_LIBADD = ../gl/libgnu.la
+noinst_LTLIBRARIES += libpkcs11mock4.la
+libpkcs11mock4_la_SOURCES = pkcs11/pkcs11-mock4.c
@ -25,17 +25,17 @@ index 1019f6c1d8..467284925a 100644
pkcs11_cert_import_url_exts_SOURCES = pkcs11/pkcs11-cert-import-url-exts.c
pkcs11_cert_import_url_exts_DEPENDENCIES = libpkcs11mock1.la libutils.la
@@ -586,6 +591,7 @@ TESTS_ENVIRONMENT += \
CAFILE=$(srcdir)/cert-tests/data/ca-certs.pem \
@@ -655,6 +660,7 @@ TESTS_ENVIRONMENT += \
P11MOCKLIB1=$(abs_builddir)/.libs/libpkcs11mock1.so \
P11MOCKLIB2=$(abs_builddir)/.libs/libpkcs11mock2.so \
P11MOCKLIB3=$(abs_builddir)/.libs/libpkcs11mock3.so \
+ P11MOCKLIB4=$(abs_builddir)/.libs/libpkcs11mock4.so \
PKCS12_MANY_CERTS_FILE=$(srcdir)/cert-tests/data/pkcs12_5certs.p12 \
PKCS12FILE=$(srcdir)/cert-tests/data/client.p12 \
PKCS12PASSWORD=foobar \
diff --git a/tests/pkcs11/pkcs11-mock4.c b/tests/pkcs11/pkcs11-mock4.c
new file mode 100644
index 0000000000..a6dd21cddd
index 000000000..a6dd21cdd
--- /dev/null
+++ b/tests/pkcs11/pkcs11-mock4.c
@@ -0,0 +1,125 @@
@ -168,7 +168,7 @@ index 0000000000..a6dd21cddd
2.52.0
From ab8ad3b005c1937ed52993cdd6a0c5e4eec98cfc Mon Sep 17 00:00:00 2001
From 87fc01fb853911e412e0fe238b069a68376ad8de Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Tue, 18 Nov 2025 13:17:55 +0900
Subject: [PATCH 2/2] pkcs11: avoid stack overwrite when initializing a token
@ -186,18 +186,18 @@ Signed-off-by: Daiki Ueno <ueno@gnu.org>
create mode 100644 tests/pkcs11/long-label.c
diff --git a/lib/pkcs11_write.c b/lib/pkcs11_write.c
index 3ce794b076..5685411ee1 100644
index f5e9058e0..64b85a2df 100644
--- a/lib/pkcs11_write.c
+++ b/lib/pkcs11_write.c
@@ -28,6 +28,7 @@
#include "pkcs11x.h"
#include <x509/common.h>
#include "x509/common.h"
#include "pk.h"
+#include "minmax.h"
static const ck_bool_t tval = 1;
static const ck_bool_t fval = 0;
@@ -1199,7 +1200,7 @@ int gnutls_pkcs11_delete_url(const char *object_url, unsigned int flags)
@@ -1172,7 +1173,7 @@ int gnutls_pkcs11_delete_url(const char *object_url, unsigned int flags)
* gnutls_pkcs11_token_init:
* @token_url: A PKCS #11 URL specifying a token
* @so_pin: Security Officer's PIN
@ -206,29 +206,31 @@ index 3ce794b076..5685411ee1 100644
*
* This function will initialize (format) a token. If the token is
* at a factory defaults state the security officer's PIN given will be
@@ -1238,7 +1239,7 @@ gnutls_pkcs11_token_init(const char *token_url,
@@ -1210,7 +1211,7 @@ int gnutls_pkcs11_token_init(const char *token_url, const char *so_pin,
/* so it seems memset has other uses than zeroing! */
memset(flabel, ' ', sizeof(flabel));
if (label != NULL)
- memcpy(flabel, label, strlen(label));
+ memcpy(flabel, label, MIN(sizeof(flabel), strlen(label)));
rv = pkcs11_init_token(module, slot, (uint8_t *) so_pin,
strlen(so_pin), (uint8_t *) flabel);
rv = pkcs11_init_token(module, slot, (uint8_t *)so_pin, strlen(so_pin),
(uint8_t *)flabel);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 467284925a..ed8b7e19c3 100644
index 62c4ec2f9..0e4d04342 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -488,11 +488,13 @@ buffer_CPPFLAGS = $(AM_CPPFLAGS) \
@@ -508,13 +508,15 @@ pathbuf_CPPFLAGS = $(AM_CPPFLAGS) \
if ENABLE_PKCS11
if !WINDOWS
ctests += tls13/post-handshake-with-cert-pkcs11 pkcs11/tls-neg-pkcs11-no-key \
- global-init-override
+ global-init-override pkcs11/long-label
- global-init-override pkcs11/distrust-after
+ global-init-override pkcs11/distrust-after pkcs11/long-label
tls13_post_handshake_with_cert_pkcs11_DEPENDENCIES = libpkcs11mock2.la libutils.la
tls13_post_handshake_with_cert_pkcs11_LDADD = $(LDADD) $(LIBDL)
pkcs11_tls_neg_pkcs11_no_key_DEPENDENCIES = libpkcs11mock2.la libutils.la
pkcs11_tls_neg_pkcs11_no_key_LDADD = $(LDADD) $(LIBDL)
pkcs11_distrust_after_DEPENDENCIES = libpkcs11mock3.la libutils.la
pkcs11_distrust_after_LDADD = $(LDADD) $(LIBDL)
+pkcs11_long_label_DEPENDENCIES = libpkcs11mock4.la libutils.la
+pkcs11_long_label_LDADD = $(LDADD) $(LIBDL)
endif
@ -236,7 +238,7 @@ index 467284925a..ed8b7e19c3 100644
diff --git a/tests/pkcs11/long-label.c b/tests/pkcs11/long-label.c
new file mode 100644
index 0000000000..a70bc97284
index 000000000..a70bc9728
--- /dev/null
+++ b/tests/pkcs11/long-label.c
@@ -0,0 +1,164 @@

View File

@ -0,0 +1,295 @@
From 5376a0cabf94314316005e6bf411ffcc7628b386 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Tue, 22 Jul 2025 10:49:33 +0900
Subject: [PATCH 1/3] key_update: fix state transition in KTLS code path
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/record.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/record.c b/lib/record.c
index d37f79a550..ebc75addec 100644
--- a/lib/record.c
+++ b/lib/record.c
@@ -2045,7 +2045,7 @@ ssize_t gnutls_record_send2(gnutls_session_t session, const void *data,
FALLTHROUGH;
case RECORD_SEND_KEY_UPDATE_3:
if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND)) {
- return _gnutls_ktls_send(
+ ret = _gnutls_ktls_send(
session,
session->internals.record_key_update_buffer.data,
session->internals.record_key_update_buffer
--
GitLab
From 30c264b661d49d135ef342426c6c4cd853209c06 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Thu, 31 Jul 2025 15:34:48 +0900
Subject: [PATCH 2/3] constate: switch epoch lookup to linear search
The previous logic of epoch lookup was utilizing the fact that epoch
numbers are monotonically increasing and there are no gaps in between
after garbarge collection. That is, however, no longer true when a TLS
1.3 key update is happening in only one direction.
This patch switches to using linear search instead, at the cost of
approx MAX_EPOCH_INDEX * 2 (= 8) comparison.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/constate.c | 47 ++++++++++++++++-------------------------------
lib/gnutls_int.h | 3 ---
2 files changed, 16 insertions(+), 34 deletions(-)
diff --git a/lib/constate.c b/lib/constate.c
index ca253a2bea..b091d891ff 100644
--- a/lib/constate.c
+++ b/lib/constate.c
@@ -932,17 +932,23 @@ static inline int epoch_resolve(gnutls_session_t session,
static inline record_parameters_st **epoch_get_slot(gnutls_session_t session,
uint16_t epoch)
{
- uint16_t epoch_index = epoch - session->security_parameters.epoch_min;
+ /* First look for a non-empty slot */
+ for (size_t i = 0; i < MAX_EPOCH_INDEX; i++) {
+ record_parameters_st **slot = &session->record_parameters[i];
+ if (*slot != NULL && (*slot)->epoch == epoch)
+ return slot;
+ }
- if (epoch_index >= MAX_EPOCH_INDEX) {
- _gnutls_handshake_log(
- "Epoch %d out of range (idx: %d, max: %d)\n",
- (int)epoch, (int)epoch_index, MAX_EPOCH_INDEX);
- gnutls_assert();
- return NULL;
+ /* Then look for an empty slot */
+ for (size_t i = 0; i < MAX_EPOCH_INDEX; i++) {
+ record_parameters_st **slot = &session->record_parameters[i];
+ if (*slot == NULL)
+ return slot;
}
- /* The slot may still be empty (NULL) */
- return &session->record_parameters[epoch_index];
+
+ gnutls_assert();
+ _gnutls_handshake_log("No slot available for epoch %u\n", epoch);
+ return NULL;
}
int _gnutls_epoch_get(gnutls_session_t session, unsigned int epoch_rel,
@@ -1063,8 +1069,7 @@ static inline int epoch_alive(gnutls_session_t session,
void _gnutls_epoch_gc(gnutls_session_t session)
{
- int i, j;
- unsigned int min_index = 0;
+ int i;
_gnutls_record_log("REC[%p]: Start of epoch cleanup\n", session);
@@ -1091,26 +1096,6 @@ void _gnutls_epoch_gc(gnutls_session_t session)
}
}
- /* Look for contiguous NULLs at the start of the array */
- for (i = 0;
- i < MAX_EPOCH_INDEX && session->record_parameters[i] == NULL; i++)
- ;
- min_index = i;
-
- /* Pick up the slack in the epoch window. */
- if (min_index != 0) {
- for (i = 0, j = min_index; j < MAX_EPOCH_INDEX; i++, j++) {
- session->record_parameters[i] =
- session->record_parameters[j];
- session->record_parameters[j] = NULL;
- }
- }
-
- /* Set the new epoch_min */
- if (session->record_parameters[0] != NULL)
- session->security_parameters.epoch_min =
- session->record_parameters[0]->epoch;
-
gnutls_mutex_unlock(&session->internals.epoch_lock);
_gnutls_record_log("REC[%p]: End of epoch cleanup\n", session);
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 539486bc7d..e083520055 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -876,9 +876,6 @@ typedef struct {
/* The epoch that the next handshake will initialize. */
uint16_t epoch_next;
- /* The epoch at index 0 of record_parameters. */
- uint16_t epoch_min;
-
/* this is the ciphersuite we are going to use
* moved here from internals in order to be restored
* on resume;
--
GitLab
From 1d830baac2f8a08a40b13e9eecfcc64ad032e7b5 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Sat, 19 Jul 2025 07:08:24 +0900
Subject: [PATCH 3/3] key_update: rework the rekeying logic
While RFC 8446 4.6.3 says that the sender of a KeyUpdate message
should only update its sending key, the previous implementation
updated both the sending and receiving keys, preventing that any
application data interleaved being decrypted.
This splits the key update logic into 2 phases: when sending a
KeyUpdate, only update the sending key, and when receiving a
KeyUpdate, only update the receiving key. In both cases, KeyUpdate
messages are encrypted/decrypted with the old keys.
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/gnutls_int.h | 2 +-
lib/tls13/key_update.c | 72 +++++++++++++++++++++++++++---------------
2 files changed, 47 insertions(+), 27 deletions(-)
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index e083520055..f3caea1170 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -1672,7 +1672,7 @@ typedef struct {
} internals_st;
/* Maximum number of epochs we keep around. */
-#define MAX_EPOCH_INDEX 4
+#define MAX_EPOCH_INDEX 16
#define reset_cand_groups(session) \
session->internals.cand_ec_group = session->internals.cand_dh_group = \
diff --git a/lib/tls13/key_update.c b/lib/tls13/key_update.c
index 41243651b5..beee1dc41a 100644
--- a/lib/tls13/key_update.c
+++ b/lib/tls13/key_update.c
@@ -52,45 +52,47 @@ static inline int set_ktls_keys(gnutls_session_t session,
return 0;
}
-static int update_keys(gnutls_session_t session, hs_stage_t stage)
+static int update_sending_key(gnutls_session_t session, hs_stage_t stage)
{
int ret;
- ret = _tls13_update_secret(session,
- session->key.proto.tls13.temp_secret,
- session->key.proto.tls13.temp_secret_size);
+ _gnutls_epoch_bump(session);
+ ret = _gnutls_epoch_dup(session, EPOCH_WRITE_CURRENT);
if (ret < 0)
return gnutls_assert_val(ret);
- _gnutls_epoch_bump(session);
- ret = _gnutls_epoch_dup(session, EPOCH_READ_CURRENT);
+ ret = _tls13_write_connection_state_init(session, stage);
if (ret < 0)
return gnutls_assert_val(ret);
- /* If we send a key update during early start, only update our
- * write keys */
- if (session->internals.recv_state == RECV_STATE_EARLY_START) {
- ret = _tls13_write_connection_state_init(session, stage);
+ if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND)) {
+ ret = set_ktls_keys(session, GNUTLS_KTLS_SEND);
if (ret < 0)
return gnutls_assert_val(ret);
+ }
- if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND))
- ret = set_ktls_keys(session, GNUTLS_KTLS_SEND);
- } else {
- ret = _tls13_connection_state_init(session, stage);
- if (ret < 0)
- return gnutls_assert_val(ret);
+ return 0;
+}
- if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND) &&
- stage == STAGE_UPD_OURS)
- ret = set_ktls_keys(session, GNUTLS_KTLS_SEND);
- else if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_RECV) &&
- stage == STAGE_UPD_PEERS)
- ret = set_ktls_keys(session, GNUTLS_KTLS_RECV);
- }
+static int update_receiving_key(gnutls_session_t session, hs_stage_t stage)
+{
+ int ret;
+
+ _gnutls_epoch_bump(session);
+ ret = _gnutls_epoch_dup(session, EPOCH_READ_CURRENT);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _tls13_read_connection_state_init(session, stage);
if (ret < 0)
return gnutls_assert_val(ret);
+ if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_RECV)) {
+ ret = set_ktls_keys(session, GNUTLS_KTLS_RECV);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+
return 0;
}
@@ -128,7 +130,13 @@ int _gnutls13_recv_key_update(gnutls_session_t session, gnutls_buffer_st *buf)
switch (buf->data[0]) {
case 0:
/* peer updated its key, not requested our key update */
- ret = update_keys(session, STAGE_UPD_PEERS);
+ ret = _tls13_update_secret(
+ session, session->key.proto.tls13.temp_secret,
+ session->key.proto.tls13.temp_secret_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = update_receiving_key(session, STAGE_UPD_PEERS);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -141,7 +149,13 @@ int _gnutls13_recv_key_update(gnutls_session_t session, gnutls_buffer_st *buf)
}
/* peer updated its key, requested our key update */
- ret = update_keys(session, STAGE_UPD_PEERS);
+ ret = _tls13_update_secret(
+ session, session->key.proto.tls13.temp_secret,
+ session->key.proto.tls13.temp_secret_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = update_receiving_key(session, STAGE_UPD_PEERS);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -248,7 +262,13 @@ int gnutls_session_key_update(gnutls_session_t session, unsigned flags)
_gnutls_epoch_gc(session);
/* it was completely sent, update the keys */
- ret = update_keys(session, STAGE_UPD_OURS);
+ ret = _tls13_update_secret(session,
+ session->key.proto.tls13.temp_secret,
+ session->key.proto.tls13.temp_secret_size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = update_sending_key(session, STAGE_UPD_OURS);
if (ret < 0)
return gnutls_assert_val(ret);
--
GitLab

View File

@ -0,0 +1,51 @@
commit b493de9ba31636de2f3b0c1dafab39b6412550bd
Author: Alexander Sosedkin <asosedkin@redhat.com>
Date: Wed Nov 19 10:46:52 2025 +0100
Revert "pkcs12: enable PBMAC1 by default in FIPS mode"
This reverts commit e52c7ca885798c40efb4ed6505e0690fc38c7dde.
diff --git a/lib/x509/pkcs12.c b/lib/x509/pkcs12.c
index a71f3ee561..18aae0bd49 100644
--- a/lib/x509/pkcs12.c
+++ b/lib/x509/pkcs12.c
@@ -997,12 +997,6 @@ int gnutls_pkcs12_generate_mac3(gnutls_pkcs12_t pkcs12,
if (me->oid == NULL)
return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
- /* Enable PBMAC1 by default in FIPS mode; otherwise the MAC
- * calculation will be FIPS non-compliant.
- */
- if (_gnutls_fips_mode_enabled())
- flags |= GNUTLS_PKCS12_USE_PBMAC1;
-
/* Generate the salt.
*/
salt.data = salt_data;
diff --git a/tests/cert-tests/pkcs12-pbmac1.sh b/tests/cert-tests/pkcs12-pbmac1.sh
index 0c2a16b52c..ef72c0a1c4 100644
--- a/tests/cert-tests/pkcs12-pbmac1.sh
+++ b/tests/cert-tests/pkcs12-pbmac1.sh
@@ -109,21 +109,6 @@ if test ${rc} != 0; then
exit 1
fi
-# check if PBMAC1 is used by default in FIPS mode
-if test "$GNUTLS_FORCE_FIPS_MODE" = 1; then
- ${VALGRIND} "$CERTTOOL" --to-p12 --password 1234 --p12-name "my-key" --load-certificate "$srcdir/../certs/cert-ecc256.pem" --load-privkey "$srcdir/../certs/ecc256.pem" --outder --outfile "$TMPFILE" >/dev/null
- rc=$?
- if test $rc != 0; then
- echo "PKCS12 FATAL encoding"
- exit 1
- fi
- ${VALGRIND} "$CERTTOOL" -d 99 --p12-info --inder --password 1234 \
- --infile "$TMPFILE" | grep "^ MAC: PBMAC1" || {
- echo "Generated PKCS12 file doesn't use PBMAC1 in FIPS mode"
- exit 1
- }
-fi
-
rm -rf "${testdir}"
exit 0

View File

@ -0,0 +1,75 @@
commit bf374b4151c7f6cf4b94e9eb911ceb730904a44c
Author: Alexander Sosedkin <asosedkin@redhat.com>
Date: Wed Nov 19 10:48:51 2025 +0100
Revert "fips: Allow SigVer only with RSA keys with modulus >= 2048 bits"
This reverts commit da1df0a3167ec96605fed267d97f9081cf498eec.
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index 5986a410c2..d14efbaaf0 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -2474,12 +2474,16 @@ static int _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
bits = mpz_sizeinbase(pub.n, 2);
- /* In FIPS 140-3, RSA key size should be larger than 2048-bit.
+ /* In FIPS 140-3, RSA key size should be larger than
+ * 2048-bit or one of the known lengths (1024, 1280,
+ * 1536, 1792; i.e., multiple of 256-bits).
+ *
* In addition to this, only SHA-2 is allowed
* for SigVer; it is checked in _pkcs1_rsa_verify_sig in
* lib/pubkey.c.
*/
- if (unlikely(bits < 2048)) {
+ if (unlikely(bits < 2048 && bits != 1024 && bits != 1280 &&
+ bits != 1536 && bits != 1792)) {
not_approved = true;
}
diff --git a/tests/fips-rsa-sizes.c b/tests/fips-rsa-sizes.c
index 61a76d3c09..d134a35f8c 100644
--- a/tests/fips-rsa-sizes.c
+++ b/tests/fips-rsa-sizes.c
@@ -250,24 +250,35 @@ void doit(void)
assert(gnutls_fips140_context_init(&fips_context) == 0);
+ /* 512-bit RSA: no generate, no sign, no verify */
generate_unsuccessfully(&privkey, &pubkey, 512);
sign_verify_unsuccessfully(privkey, pubkey);
+ /* 512-bit RSA again (to be safer about going in and out of FIPS) */
generate_unsuccessfully(&privkey, &pubkey, 512);
sign_verify_unsuccessfully(privkey, pubkey);
+ /* 600-bit RSA: no generate, no sign, no verify */
generate_unsuccessfully(&privkey, &pubkey, 600);
sign_verify_unsuccessfully(privkey, pubkey);
+
+ /* 768-bit RSA not-an-exception: nogenerate, nosign, verify */
generate_unsuccessfully(&privkey, &pubkey, 768);
sign_verify_unsuccessfully(privkey, pubkey);
+ /* 1024-bit RSA exception: nogenerate, nosign, verify */
generate_unsuccessfully(&privkey, &pubkey, 1024);
- sign_verify_unsuccessfully(privkey, pubkey);
+ nosign_verify(privkey, pubkey);
+ /* 1280-bit RSA exception: nogenerate, nosign, verify */
generate_unsuccessfully(&privkey, &pubkey, 1280);
- sign_verify_unsuccessfully(privkey, pubkey);
+ nosign_verify(privkey, pubkey);
+ /* 1500-bit RSA not-an-exception: nogenerate, nosign, noverify */
generate_unsuccessfully(&privkey, &pubkey, 1500);
sign_verify_unsuccessfully(privkey, pubkey);
+ /* 1536-bit RSA exception: nogenerate, nosign, verify */
generate_unsuccessfully(&privkey, &pubkey, 1536);
- sign_verify_unsuccessfully(privkey, pubkey);
+ nosign_verify(privkey, pubkey);
+ /* 1792-bit RSA exception: nogenerate, nosign, verify */
generate_unsuccessfully(&privkey, &pubkey, 1792);
- sign_verify_unsuccessfully(privkey, pubkey);
+ nosign_verify(privkey, pubkey);
+ /* 2000-bit RSA not-an-exception: nogenerate, nosign, noverify */
generate_unsuccessfully(&privkey, &pubkey, 2000);
sign_verify_unsuccessfully(privkey, pubkey);

View File

@ -0,0 +1,114 @@
From e0eb2bbb212a5c9d72311c59e7235832a0075dcc Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Wed, 9 Jul 2025 18:54:48 +0900
Subject: [PATCH] add tests/ktls_utils.h
Signed-off-by: rpm-build <rpm-build>
---
tests/ktls_utils.h | 94 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 94 insertions(+)
create mode 100644 tests/ktls_utils.h
diff --git a/tests/ktls_utils.h b/tests/ktls_utils.h
new file mode 100644
index 0000000..231618d
--- /dev/null
+++ b/tests/ktls_utils.h
@@ -0,0 +1,94 @@
+#ifndef GNUTLS_TESTS_KTLS_UTILS_H
+#define GNUTLS_TESTS_KTLS_UTILS_H
+
+#include <fcntl.h>
+#include <signal.h>
+
+#include <netinet/in.h>
+
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+/* Sets the NONBLOCK flag on the socket(fd) */
+inline static int set_nonblocking(int fd)
+{
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1) {
+ return 1;
+ }
+
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+ return 2;
+ }
+
+ return 0;
+}
+
+/* Creates a pair of TCP connected sockets */
+static int create_socket_pair(int *client_fd, int *server_fd)
+{
+ int ret;
+ struct sockaddr_in saddr;
+ socklen_t addrlen;
+ int listener;
+
+ listener = socket(AF_INET, SOCK_STREAM, 0);
+ if (listener == -1) {
+ fail("error in listener(): %s\n", strerror(errno));
+ return 1;
+ }
+
+ int opt = 0;
+ setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ saddr.sin_port = 0;
+
+ ret = bind(listener, (struct sockaddr *)&saddr, sizeof(saddr));
+ if (ret == -1) {
+ fail("error in bind(): %s\n", strerror(errno));
+ return 1;
+ }
+
+ addrlen = sizeof(saddr);
+ ret = getsockname(listener, (struct sockaddr *)&saddr, &addrlen);
+ if (ret == -1) {
+ fail("error in getsockname(): %s\n", strerror(errno));
+ return 1;
+ }
+
+ ret = listen(listener, 1);
+ if (ret == -1) {
+ fail("error in listen(): %s\n", strerror(errno));
+ close(listener);
+ return 1;
+ }
+
+ *client_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (*client_fd < 0) {
+ fail("error in socket(): %s\n", strerror(errno));
+ return 1;
+ }
+
+ ret = connect(*client_fd, (struct sockaddr *)&saddr, addrlen);
+ if (ret < 0) {
+ fail("error in connect(): %s\n", strerror(errno));
+ close(listener);
+ close(*client_fd);
+ return 1;
+ }
+
+ *server_fd = accept(listener, NULL, NULL);
+ if (*server_fd < 0) {
+ fail("error in accept(): %s\n", strerror(errno));
+ close(listener);
+ close(*client_fd);
+ return 1;
+ }
+
+ return 0;
+}
+
+#endif //GNUTLS_TESTS_KTLS_UTILS_H
--
2.49.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,226 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
wNTn8cXhFYi0Of02Vt4nNiXryBL/zneXgb37qiI=
=8Avy
-----END PGP PUBLIC KEY BLOCK-----

File diff suppressed because it is too large Load Diff