gnutls/gnutls-3.7.8-ktls_key_update.patch
Frantisek Krenzelok c1f8e66db2
KTLS additional ciphersuites
Key update supported for patched kernels [1]

Configuration option `ktls = false` [2]

following ciphersuites are now supported: [3]
* TLS_AES_128_CCM_SHA256
* TLS_CHACHA20_POLY1305_SHA256

Ivalidate session on KTLS error as there is no way to recover and new
sockets as well as session have to be created. [4]

[1] https://gitlab.com/gnutls/gnutls/-/merge_requests/1625
[2] https://gitlab.com/gnutls/gnutls/-/merge_requests/1673/diffs?commit_id=aefd7319c0b7b2410d06238246b7755b289e4837
[3] https://gitlab.com/gnutls/gnutls/-/merge_requests/1676
[4] https://gitlab.com/gnutls/gnutls/-/merge_requests/1664

Signed-off-by: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
2023-01-20 19:17:15 +01:00

958 lines
27 KiB
Diff

From c83b9ecbe8e7e5442867281236d8c9e1bd227204 Mon Sep 17 00:00:00 2001
From: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
Date: Tue, 2 Aug 2022 15:00:50 +0200
Subject: [PATCH 1/7] KTLS: set key on specific interfaces
It is now possible to set key on specific interface.
If interface given is not ktls enabled then it will be ignored.
Signed-off-by: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
---
lib/handshake.c | 2 +-
lib/system/ktls.c | 12 +++++++-----
lib/system/ktls.h | 7 ++++++-
3 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/lib/handshake.c b/lib/handshake.c
index 21edc5ece..cb2bc3ae9 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -2924,7 +2924,7 @@ int gnutls_handshake(gnutls_session_t session)
#ifdef ENABLE_KTLS
if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_DUPLEX)) {
- _gnutls_ktls_set_keys(session);
+ _gnutls_ktls_set_keys(session, GNUTLS_KTLS_DUPLEX);
}
#endif
diff --git a/lib/system/ktls.c b/lib/system/ktls.c
index ddf27fac7..70b9b9b3a 100644
--- a/lib/system/ktls.c
+++ b/lib/system/ktls.c
@@ -80,7 +80,7 @@ void _gnutls_ktls_enable(gnutls_session_t session)
}
}
-int _gnutls_ktls_set_keys(gnutls_session_t session)
+int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable_flags_t in)
{
gnutls_cipher_algorithm_t cipher = gnutls_cipher_get(session);
gnutls_datum_t mac_key;
@@ -107,7 +107,9 @@ int _gnutls_ktls_set_keys(gnutls_session_t session)
return ret;
}
- if(session->internals.ktls_enabled & GNUTLS_KTLS_RECV){
+ in &= session->internals.ktls_enabled;
+
+ if(in & GNUTLS_KTLS_RECV){
switch (cipher) {
case GNUTLS_CIPHER_AES_128_GCM:
{
@@ -191,7 +193,7 @@ int _gnutls_ktls_set_keys(gnutls_session_t session)
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
}
- if(session->internals.ktls_enabled & GNUTLS_KTLS_SEND){
+ if(in & GNUTLS_KTLS_SEND){
switch (cipher) {
case GNUTLS_CIPHER_AES_128_GCM:
{
@@ -269,7 +271,7 @@ int _gnutls_ktls_set_keys(gnutls_session_t session)
}
}
- return 0;
+ return in;
}
ssize_t _gnutls_ktls_send_file(gnutls_session_t session, int fd,
@@ -465,7 +467,7 @@ gnutls_transport_is_ktls_enabled(gnutls_session_t session) {
void _gnutls_ktls_enable(gnutls_session_t session) {
}
-int _gnutls_ktls_set_keys(gnutls_session_t session) {
+int _gnutls_ktls_set_keys(gnutls_session_t sessioni, gnutls_transport_ktls_enable_flags_t in) {
return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
}
diff --git a/lib/system/ktls.h b/lib/system/ktls.h
index 8a98a8eb8..c8059092d 100644
--- a/lib/system/ktls.h
+++ b/lib/system/ktls.h
@@ -4,14 +4,19 @@
#include "gnutls_int.h"
void _gnutls_ktls_enable(gnutls_session_t session);
-int _gnutls_ktls_set_keys(gnutls_session_t session);
+
+int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable_flags_t in);
+
ssize_t _gnutls_ktls_send_file(gnutls_session_t session, int fd,
off_t *offset, size_t count);
+
int _gnutls_ktls_send_control_msg(gnutls_session_t session, unsigned char record_type,
const void *data, size_t data_size);
#define _gnutls_ktls_send(x, y, z) _gnutls_ktls_send_control_msg(x, GNUTLS_APPLICATION_DATA, y, z);
+
int _gnutls_ktls_recv_control_msg(gnutls_session_t session, unsigned char *record_type,
void *data, size_t data_size);
+
int _gnutls_ktls_recv_int(gnutls_session_t session, content_type_t type, void *data, size_t data_size);
#define _gnutls_ktls_recv(x, y, z) _gnutls_ktls_recv_int(x, GNUTLS_APPLICATION_DATA, y, z)
--
2.39.0
From f8c71030151e3a0d397e9712541236f1a76434a3 Mon Sep 17 00:00:00 2001
From: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
Date: Tue, 2 Aug 2022 13:35:39 +0200
Subject: [PATCH 2/7] KTLS: set new keys for keyupdate
set new keys durring gnutls_session_key_update()
setting keys
Signed-off-by: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
---
lib/tls13/key_update.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/lib/tls13/key_update.c b/lib/tls13/key_update.c
index c6f6e0aa1..10c0a9110 100644
--- a/lib/tls13/key_update.c
+++ b/lib/tls13/key_update.c
@@ -27,6 +27,7 @@
#include "mem.h"
#include "mbuffers.h"
#include "secrets.h"
+#include "system/ktls.h"
#define KEY_UPDATES_WINDOW 1000
#define KEY_UPDATES_PER_WINDOW 8
@@ -49,8 +50,16 @@ static int update_keys(gnutls_session_t session, hs_stage_t stage)
* 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 = _gnutls_ktls_set_keys(session, GNUTLS_KTLS_SEND);
} else {
ret = _tls13_connection_state_init(session, stage);
+
+ if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND) && stage == STAGE_UPD_OURS)
+ ret = _gnutls_ktls_set_keys(session, GNUTLS_KTLS_SEND);
+ else if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_RECV) && stage == STAGE_UPD_PEERS)
+ ret = _gnutls_ktls_set_keys(session, GNUTLS_KTLS_RECV);
+
}
if (ret < 0)
return gnutls_assert_val(ret);
--
2.39.0
From b93af37d972e02b095e14d4209bf5d5520a4893c Mon Sep 17 00:00:00 2001
From: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
Date: Wed, 3 Aug 2022 14:20:35 +0200
Subject: [PATCH 3/7] KTLS: send update key request
Set hanshake send function after interface initialization
TODO: handel setting function differently
Signed-off-by: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
---
lib/record.c | 23 ++++++++++++++++-------
lib/system/ktls.c | 21 +++++++++++++++++++++
lib/system/ktls.h | 5 +++++
3 files changed, 42 insertions(+), 7 deletions(-)
diff --git a/lib/record.c b/lib/record.c
index fd24acaf1..aad128e1f 100644
--- a/lib/record.c
+++ b/lib/record.c
@@ -2065,11 +2065,17 @@ gnutls_record_send2(gnutls_session_t session, const void *data,
session->internals.rsend_state = RECORD_SEND_KEY_UPDATE_3;
FALLTHROUGH;
case RECORD_SEND_KEY_UPDATE_3:
- ret = _gnutls_send_int(session, GNUTLS_APPLICATION_DATA,
- -1, EPOCH_WRITE_CURRENT,
- session->internals.record_key_update_buffer.data,
- session->internals.record_key_update_buffer.length,
- MBUFFER_FLUSH);
+ if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND)) {
+ return _gnutls_ktls_send(session,
+ session->internals.record_key_update_buffer.data,
+ session->internals.record_key_update_buffer.length);
+ } else {
+ ret = _gnutls_send_int(session, GNUTLS_APPLICATION_DATA,
+ -1, EPOCH_WRITE_CURRENT,
+ session->internals.record_key_update_buffer.data,
+ session->internals.record_key_update_buffer.length,
+ MBUFFER_FLUSH);
+ }
_gnutls_buffer_clear(&session->internals.record_key_update_buffer);
session->internals.rsend_state = RECORD_SEND_NORMAL;
if (ret < 0)
@@ -2494,8 +2500,11 @@ gnutls_handshake_write(gnutls_session_t session,
return gnutls_assert_val(0);
/* When using this, the outgoing handshake messages should
- * also be handled manually */
- if (!session->internals.h_read_func)
+ * also be handled manually unless KTLS is enabled exclusively
+ * in GNUTLS_KTLS_RECV mode in which case the outgoing messages
+ * are handled by GnuTLS.
+ */
+ if (!session->internals.h_read_func && !IS_KTLS_ENABLED(session, GNUTLS_KTLS_RECV))
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
if (session->internals.initial_negotiation_completed) {
diff --git a/lib/system/ktls.c b/lib/system/ktls.c
index 70b9b9b3a..5da0a8069 100644
--- a/lib/system/ktls.c
+++ b/lib/system/ktls.c
@@ -269,6 +269,9 @@ int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable
default:
assert(0);
}
+ // set callback for sending handshake messages
+ gnutls_handshake_set_read_function(session,
+ _gnutls_ktls_send_handshake_msg);
}
return in;
@@ -355,6 +358,15 @@ int _gnutls_ktls_send_control_msg(gnutls_session_t session,
return data_size;
}
+int _gnutls_ktls_send_handshake_msg(gnutls_session_t session,
+ gnutls_record_encryption_level_t level,
+ gnutls_handshake_description_t htype,
+ const void *data, size_t data_size)
+{
+ return _gnutls_ktls_send_control_msg(session, GNUTLS_HANDSHAKE,
+ data, data_size);
+}
+
int _gnutls_ktls_recv_control_msg(gnutls_session_t session,
unsigned char *record_type, void *data, size_t data_size)
{
@@ -481,6 +493,15 @@ int _gnutls_ktls_send_control_msg(gnutls_session_t session,
return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
}
+int _gnutls_ktls_send_handshake_msg(gnutls_session_t session,
+ gnutls_record_encryption_level_t level,
+ gnutls_handshake_description_t htype,
+ const void *data, size_t data_size)
+{
+ (void)level;
+ return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
+}
+
int _gnutls_ktls_recv_int(gnutls_session_t session, content_type_t type,
void *data, size_t data_size) {
return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
diff --git a/lib/system/ktls.h b/lib/system/ktls.h
index c8059092d..8d61a49df 100644
--- a/lib/system/ktls.h
+++ b/lib/system/ktls.h
@@ -10,6 +10,11 @@ int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable
ssize_t _gnutls_ktls_send_file(gnutls_session_t session, int fd,
off_t *offset, size_t count);
+int _gnutls_ktls_send_handshake_msg(gnutls_session_t session,
+ gnutls_record_encryption_level_t level,
+ gnutls_handshake_description_t htype,
+ const void *data, size_t data_size);
+
int _gnutls_ktls_send_control_msg(gnutls_session_t session, unsigned char record_type,
const void *data, size_t data_size);
#define _gnutls_ktls_send(x, y, z) _gnutls_ktls_send_control_msg(x, GNUTLS_APPLICATION_DATA, y, z);
--
2.39.0
From 7128338208d092275ac72785f85019d16951fab9 Mon Sep 17 00:00:00 2001
From: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
Date: Mon, 22 Aug 2022 10:50:37 +0200
Subject: [PATCH 4/7] KTLS: receive key update
handle received GNUTLS_HANDSHAKE_KEY_UPDATE set keys accordingly
Signed-off-by: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
---
lib/system/ktls.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/lib/system/ktls.c b/lib/system/ktls.c
index 5da0a8069..f3cb343ae 100644
--- a/lib/system/ktls.c
+++ b/lib/system/ktls.c
@@ -452,7 +452,13 @@ int _gnutls_ktls_recv_int(gnutls_session_t session, content_type_t type,
ret = 0;
break;
case GNUTLS_HANDSHAKE:
- // ignore post-handshake messages
+ ret = gnutls_handshake_write(session,
+ GNUTLS_ENCRYPTION_LEVEL_APPLICATION,
+ data, ret);
+
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
if (type != record_type)
return GNUTLS_E_AGAIN;
break;
--
2.39.0
From 14eadde1f2cdfaf858dc2029dac5503e48a49935 Mon Sep 17 00:00:00 2001
From: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
Date: Fri, 5 Aug 2022 16:38:02 +0200
Subject: [PATCH 5/7] KTLS: set write alert callback
Use callback for sending alerts.
Signed-off-by: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
---
lib/alert.c | 13 ++++---------
lib/system/ktls.c | 15 +++++++++++++++
lib/system/ktls.h | 5 +++++
3 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/lib/alert.c b/lib/alert.c
index 50bd1d3de..fda8cd79f 100644
--- a/lib/alert.c
+++ b/lib/alert.c
@@ -182,15 +182,10 @@ gnutls_alert_send(gnutls_session_t session, gnutls_alert_level_t level,
return ret;
}
- if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND)) {
- ret =
- _gnutls_ktls_send_control_msg(session, GNUTLS_ALERT, data, 2);
- } else {
- ret =
- _gnutls_send_int(session, GNUTLS_ALERT, -1,
- EPOCH_WRITE_CURRENT, data, 2,
- MBUFFER_FLUSH);
- }
+ ret = _gnutls_send_int(session, GNUTLS_ALERT, -1,
+ EPOCH_WRITE_CURRENT, data, 2,
+ MBUFFER_FLUSH);
+
return (ret < 0) ? ret : 0;
}
diff --git a/lib/system/ktls.c b/lib/system/ktls.c
index f3cb343ae..703775960 100644
--- a/lib/system/ktls.c
+++ b/lib/system/ktls.c
@@ -269,9 +269,13 @@ int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable
default:
assert(0);
}
+
// set callback for sending handshake messages
gnutls_handshake_set_read_function(session,
_gnutls_ktls_send_handshake_msg);
+
+ // set callback for sending alert messages
+ gnutls_alert_set_read_function(session, _gnutls_ktls_send_alert_msg);
}
return in;
@@ -367,6 +371,17 @@ int _gnutls_ktls_send_handshake_msg(gnutls_session_t session,
data, data_size);
}
+int _gnutls_ktls_send_alert_msg(gnutls_session_t session,
+ gnutls_record_encryption_level_t level,
+ gnutls_alert_level_t alert_level,
+ gnutls_alert_description_t alert_desc)
+{
+ uint8_t data[2];
+ data[0] = (uint8_t) alert_level;
+ data[1] = (uint8_t) alert_desc;
+ return _gnutls_ktls_send_control_msg(session, GNUTLS_ALERT, data, 2);
+}
+
int _gnutls_ktls_recv_control_msg(gnutls_session_t session,
unsigned char *record_type, void *data, size_t data_size)
{
diff --git a/lib/system/ktls.h b/lib/system/ktls.h
index 8d61a49df..64e1c9c1c 100644
--- a/lib/system/ktls.h
+++ b/lib/system/ktls.h
@@ -15,6 +15,11 @@ int _gnutls_ktls_send_handshake_msg(gnutls_session_t session,
gnutls_handshake_description_t htype,
const void *data, size_t data_size);
+int _gnutls_ktls_send_alert_msg(gnutls_session_t session,
+ gnutls_record_encryption_level_t level,
+ gnutls_alert_level_t alert_level,
+ gnutls_alert_description_t alert_desc);
+
int _gnutls_ktls_send_control_msg(gnutls_session_t session, unsigned char record_type,
const void *data, size_t data_size);
#define _gnutls_ktls_send(x, y, z) _gnutls_ktls_send_control_msg(x, GNUTLS_APPLICATION_DATA, y, z);
--
2.39.0
From 38b8708d66e592c09edf2745c921436f56607a96 Mon Sep 17 00:00:00 2001
From: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
Date: Tue, 9 Aug 2022 12:11:16 +0200
Subject: [PATCH 6/7] KTLS: rekey test
Signed-off-by: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
---
tests/Makefile.am | 2 +
tests/ktls_keyupdate.c | 381 ++++++++++++++++++++++++++++++++++++++++
tests/ktls_keyupdate.sh | 46 +++++
3 files changed, 429 insertions(+)
create mode 100644 tests/ktls_keyupdate.c
create mode 100755 tests/ktls_keyupdate.sh
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 1122886b3..2d345d478 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -500,6 +500,8 @@ endif
if ENABLE_KTLS
indirect_tests += gnutls_ktls
dist_check_SCRIPTS += ktls.sh
+indirect_tests += ktls_keyupdate
+dist_check_SCRIPTS += ktls_keyupdate.sh
endif
if !WINDOWS
diff --git a/tests/ktls_keyupdate.c b/tests/ktls_keyupdate.c
new file mode 100644
index 000000000..9fbff38ae
--- /dev/null
+++ b/tests/ktls_keyupdate.c
@@ -0,0 +1,381 @@
+// Copyright (C) 2022 Red Hat, Inc.
+//
+// Author: Frantisek Krenzelok
+//
+// 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, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include <gnutls/dtls.h>
+#include <gnutls/socket.h>
+#include <signal.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "cert-common.h"
+#include "utils.h"
+
+#if defined(_WIN32)
+
+int main(void)
+{
+ exit(77);
+}
+
+#else
+
+
+#define MAX_BUF 1024
+#define MSG "Hello world!"
+
+#define HANDSHAKE(session, name, ret)\
+{\
+ do {\
+ ret = gnutls_handshake(session);\
+ }\
+ while (ret < 0 && gnutls_error_is_fatal(ret) == 0);\
+ if (ret < 0) {\
+ fail("%s: Handshake failed\n", name);\
+ goto end;\
+ }\
+}
+
+#define SEND_MSG(session, name, ret)\
+{\
+ do {\
+ ret = gnutls_record_send(session, MSG, strlen(MSG)+1);\
+ } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);\
+ if (ret < 0) {\
+ fail("%s: data sending has failed (%s)\n",name,\
+ gnutls_strerror(ret));\
+ goto end;\
+ }\
+}
+
+#define RECV_MSG(session, name, buffer, buffer_len, ret)\
+{\
+ memset(buffer, 0, sizeof(buffer));\
+ do{\
+ ret = gnutls_record_recv(session, buffer, sizeof(buffer));\
+ }\
+ while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);\
+ if (ret == 0) {\
+ success("%s: Peer has closed the TLS connection\n", name);\
+ goto end;\
+ } else if (ret < 0) {\
+ fail("%s: Error -> %s\n", name, gnutls_strerror(ret));\
+ goto end;\
+ }\
+ if(strncmp(buffer, MSG, ret)){\
+ fail("%s: Message doesn't match\n", name);\
+ goto end;\
+ }\
+}
+
+#define KEY_UPDATE(session, name, peer_req, ret)\
+{\
+ do {\
+ ret = gnutls_session_key_update(session, peer_req);\
+ } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);\
+ if (ret < 0) {\
+ fail("%s: key update has failed (%s)\n", name, \
+ gnutls_strerror(ret));\
+ goto end;\
+ }\
+}
+
+#define CHECK_KTLS_ENABLED(session, ret)\
+{\
+ ret = gnutls_transport_is_ktls_enabled(session);\
+ if (!(ret & GNUTLS_KTLS_RECV)){\
+ fail("client: KTLS was not properly initialized\n");\
+ goto end;\
+ }\
+}
+
+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);
+}
+
+
+static void client(int fd, const char *prio, int pipe)
+{
+ const char *name = "client";
+ int ret;
+ char foo;
+ char buffer[MAX_BUF + 1];
+ gnutls_certificate_credentials_t x509_cred;
+ gnutls_session_t session;
+
+ global_init();
+
+ if (debug) {
+ gnutls_global_set_log_function(client_log_func);
+ gnutls_global_set_log_level(7);
+ }
+
+ gnutls_certificate_allocate_credentials(&x509_cred);
+
+ gnutls_init(&session, GNUTLS_CLIENT);
+ gnutls_handshake_set_timeout(session, 0);
+
+ assert(gnutls_priority_set_direct(session, prio, NULL) >= 0);
+
+ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
+
+ gnutls_transport_set_int(session, fd);
+
+ HANDSHAKE(session, name, ret);
+
+ CHECK_KTLS_ENABLED(session, ret)
+
+ // Test 0: Try sending/receiving data
+ RECV_MSG(session, name, buffer, MAX_BUF+1, ret)
+ SEND_MSG(session, name, ret)
+
+ CHECK_KTLS_ENABLED(session, ret)
+
+ // Test 1: Servers does key update
+ read(pipe, &foo, 1);
+ RECV_MSG(session, name, buffer, MAX_BUF+1, ret)
+ SEND_MSG(session, name, ret)
+
+ CHECK_KTLS_ENABLED(session, ret)
+
+ // Test 2: Does key update witch request
+ read(pipe, &foo, 1);
+ RECV_MSG(session, name, buffer, MAX_BUF+1, ret)
+ SEND_MSG(session, name, ret)
+
+ CHECK_KTLS_ENABLED(session, ret)
+
+ ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
+ if (ret < 0) {
+ fail("client: error in closing session: %s\n", gnutls_strerror(ret));
+ }
+
+ ret = 0;
+ end:
+
+ close(fd);
+
+ gnutls_deinit(session);
+
+ gnutls_certificate_free_credentials(x509_cred);
+
+ gnutls_global_deinit();
+
+ if (ret != 0)
+ exit(1);
+}
+
+pid_t child;
+static void terminate(void)
+{
+ assert(child);
+ kill(child, SIGTERM);
+ exit(1);
+}
+
+static void server(int fd, const char *prio, int pipe)
+{
+ const char *name = "server";
+ int ret;
+ char bar = 0;
+ char buffer[MAX_BUF + 1];
+ gnutls_certificate_credentials_t x509_cred;
+ gnutls_session_t session;
+
+ global_init();
+
+ if (debug) {
+ gnutls_global_set_log_function(server_log_func);
+ gnutls_global_set_log_level(7);
+ }
+
+ gnutls_certificate_allocate_credentials(&x509_cred);
+ ret = gnutls_certificate_set_x509_key_mem(x509_cred, &server_cert,
+ &server_key,
+ GNUTLS_X509_FMT_PEM);
+ if (ret < 0)
+ exit(1);
+
+ gnutls_init(&session, GNUTLS_SERVER);
+ gnutls_handshake_set_timeout(session, 0);
+
+ assert(gnutls_priority_set_direct(session, prio, NULL)>=0);
+
+ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
+
+ gnutls_transport_set_int(session, fd);
+
+ HANDSHAKE(session, name, ret)
+
+ CHECK_KTLS_ENABLED(session, ret)
+
+ success("Test 0: sending/receiving data\n");
+ SEND_MSG(session, name, ret)
+ RECV_MSG(session, name, buffer, MAX_BUF+1, ret)
+
+ CHECK_KTLS_ENABLED(session, ret)
+
+ success("Test 1: server key update without request\n");
+ KEY_UPDATE(session, name, 0, ret)
+ write(pipe, &bar, 1);
+ SEND_MSG(session, name, ret)
+ RECV_MSG(session, name, buffer, MAX_BUF+1, ret)
+
+ CHECK_KTLS_ENABLED(session, ret)
+
+ success("Test 2: server key update with request\n");
+ KEY_UPDATE(session, name, GNUTLS_KU_PEER, ret)
+ write(pipe, &bar, 1);
+ SEND_MSG(session, name, ret)
+ RECV_MSG(session, name, buffer, MAX_BUF+1, ret)
+
+ CHECK_KTLS_ENABLED(session, ret)
+
+ ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
+ if (ret < 0) {
+ fail("server: error in closing session: %s\n", gnutls_strerror(ret));
+ }
+
+ ret = 0;
+end:
+ close(fd);
+ gnutls_deinit(session);
+
+ gnutls_certificate_free_credentials(x509_cred);
+
+ gnutls_global_deinit();
+
+ if (ret){
+ terminate();
+ }
+
+ if (debug)
+ success("server: finished\n");
+}
+
+static void ch_handler(int sig)
+{
+ return;
+}
+
+static void run(const char *prio)
+{
+ int ret;
+ struct sockaddr_in saddr;
+ socklen_t addrlen;
+ int listener;
+ int fd;
+
+ int sync_pipe[2]; //used for synchronization
+ pipe(sync_pipe);
+
+ success("running ktls test with %s\n", prio);
+
+ signal(SIGCHLD, ch_handler);
+ signal(SIGPIPE, SIG_IGN);
+
+ listener = socket(AF_INET, SOCK_STREAM, 0);
+ if (listener == -1){
+ fail("error in listener(): %s\n", strerror(errno));
+ }
+
+ 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));
+ }
+
+ addrlen = sizeof(saddr);
+ ret = getsockname(listener, (struct sockaddr*)&saddr, &addrlen);
+ if (ret == -1){
+ fail("error in getsockname(): %s\n", strerror(errno));
+ }
+
+ child = fork();
+ if (child < 0) {
+ fail("error in fork(): %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (child) {
+ int status;
+ /* parent */
+ ret = listen(listener, 1);
+ if (ret == -1) {
+ fail("error in listen(): %s\n", strerror(errno));
+ }
+
+ fd = accept(listener, NULL, NULL);
+ if (fd == -1) {
+ fail("error in accept(): %s\n", strerror(errno));
+ }
+
+ close(sync_pipe[0]);
+ server(fd, prio, sync_pipe[1]);
+
+ wait(&status);
+ check_wait_status(status);
+ } else {
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd == -1){
+ fail("error in socket(): %s\n", strerror(errno));
+ exit(1);
+ }
+
+ usleep(1000000);
+ connect(fd, (struct sockaddr*)&saddr, addrlen);
+
+ close(sync_pipe[1]);
+ client(fd, prio, sync_pipe[0]);
+ exit(0);
+ }
+}
+
+void doit(void)
+{
+ run("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM");
+ run("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-256-GCM");
+}
+
+#endif /* _WIN32 */
diff --git a/tests/ktls_keyupdate.sh b/tests/ktls_keyupdate.sh
new file mode 100755
index 000000000..d072acafc
--- /dev/null
+++ b/tests/ktls_keyupdate.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# 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 General Public License
+# along with GnuTLS; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+: ${builddir=.}
+
+. "$srcdir/scripts/common.sh"
+
+if ! grep '^tls ' /proc/modules 2>&1 /dev/null; then
+ exit 77
+fi
+
+testdir=`create_testdir ktls_keyupdate`
+
+cfg="$testdir/config"
+
+cat <<EOF > "$cfg"
+[global]
+ktls = true
+EOF
+
+GNUTLS_SYSTEM_PRIORITY_FAIL_ON_INVALID=1 \
+GNUTLS_SYSTEM_PRIORITY_FILE="$cfg" \
+"$builddir/ktls_keyupdate" "$@"
+rc=$?
+
+rm -rf "$testdir"
+exit $rc
--
2.39.0
From 67843b3a8e28e4c74296caea2d1019065c87afb3 Mon Sep 17 00:00:00 2001
From: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
Date: Mon, 5 Sep 2022 13:05:17 +0200
Subject: [PATCH 7/7] KTLS: fallback to default
If an error occurs during setting of keys either initial or key update
then fallback to default mode of operation (disable ktls) and let the
user know
Signed-off-by: Frantisek Krenzelok <krenzelok.frantisek@gmail.com>
---
lib/handshake.c | 7 ++++++-
lib/tls13/key_update.c | 23 +++++++++++++++++++----
2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/lib/handshake.c b/lib/handshake.c
index cb2bc3ae9..14bcdea56 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -2924,7 +2924,12 @@ int gnutls_handshake(gnutls_session_t session)
#ifdef ENABLE_KTLS
if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_DUPLEX)) {
- _gnutls_ktls_set_keys(session, GNUTLS_KTLS_DUPLEX);
+ ret = _gnutls_ktls_set_keys(session, GNUTLS_KTLS_DUPLEX);
+ if (ret < 0) {
+ session->internals.ktls_enabled = 0;
+ _gnutls_audit_log(session,
+ "disabling KTLS: failed to set keys\n");
+ }
}
#endif
diff --git a/lib/tls13/key_update.c b/lib/tls13/key_update.c
index 10c0a9110..acfda4129 100644
--- a/lib/tls13/key_update.c
+++ b/lib/tls13/key_update.c
@@ -32,6 +32,20 @@
#define KEY_UPDATES_WINDOW 1000
#define KEY_UPDATES_PER_WINDOW 8
+/*
+ * Sets kTLS keys if enabled.
+ * If this operation fails with GNUTLS_E_INTERNAL_ERROR, KTLS is disabled
+ * because KTLS most likely doesn't support key update.
+ */
+#define SET_KTLS_KEYS(session, interface)\
+{\
+ if(_gnutls_ktls_set_keys(session, interface) < 0) {\
+ session->internals.ktls_enabled = 0;\
+ _gnutls_audit_log(session, \
+ "disabling KTLS: couldn't update keys\n");\
+ }\
+}
+
static int update_keys(gnutls_session_t session, hs_stage_t stage)
{
int ret;
@@ -51,15 +65,16 @@ static int update_keys(gnutls_session_t session, hs_stage_t stage)
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 = _gnutls_ktls_set_keys(session, GNUTLS_KTLS_SEND);
+ SET_KTLS_KEYS(session, GNUTLS_KTLS_SEND)
} else {
ret = _tls13_connection_state_init(session, stage);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_SEND) && stage == STAGE_UPD_OURS)
- ret = _gnutls_ktls_set_keys(session, GNUTLS_KTLS_SEND);
+ SET_KTLS_KEYS(session, GNUTLS_KTLS_SEND)
else if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_RECV) && stage == STAGE_UPD_PEERS)
- ret = _gnutls_ktls_set_keys(session, GNUTLS_KTLS_RECV);
-
+ SET_KTLS_KEYS(session, GNUTLS_KTLS_RECV)
}
if (ret < 0)
return gnutls_assert_val(ret);
--
2.39.0