From c1f8e66db2fe6753da67a3b3dbd241ebdb85b7d9 Mon Sep 17 00:00:00 2001 From: Frantisek Krenzelok Date: Jan 20 2023 18:17:15 +0000 Subject: 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 --- diff --git a/gnutls-3.7.8-ktls_add_ciphersuites.patch b/gnutls-3.7.8-ktls_add_ciphersuites.patch new file mode 100644 index 0000000..88ae1aa --- /dev/null +++ b/gnutls-3.7.8-ktls_add_ciphersuites.patch @@ -0,0 +1,273 @@ +From 4380f347b2fff4af10537930400b68df61bee442 Mon Sep 17 00:00:00 2001 +From: Frantisek Krenzelok +Date: Thu, 1 Dec 2022 15:37:33 +0100 +Subject: [PATCH 1/2] KTLS: add ciphersuites + +* TLS_AES_128_CCM_SHA256 +* TLS_CHACHA20_POLY1305_SHA256 + +Signed-off-by: Frantisek Krenzelok +--- + lib/system/ktls.c | 159 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 153 insertions(+), 6 deletions(-) + +diff --git a/lib/system/ktls.c b/lib/system/ktls.c +index 703775960..792d09ccf 100644 +--- a/lib/system/ktls.c ++++ b/lib/system/ktls.c +@@ -86,7 +86,7 @@ int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable + gnutls_datum_t mac_key; + gnutls_datum_t iv; + gnutls_datum_t cipher_key; +- unsigned char seq_number[8]; ++ unsigned char seq_number[12]; + int sockin, sockout; + int ret; + +@@ -97,7 +97,9 @@ int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable + int version = gnutls_protocol_get_version(session); + if ((version != GNUTLS_TLS1_3 && version != GNUTLS_TLS1_2) || + (gnutls_cipher_get(session) != GNUTLS_CIPHER_AES_128_GCM && +- gnutls_cipher_get(session) != GNUTLS_CIPHER_AES_256_GCM)) { ++ gnutls_cipher_get(session) != GNUTLS_CIPHER_AES_256_GCM && ++ gnutls_cipher_get(session) != GNUTLS_CIPHER_AES_128_CCM && ++ gnutls_cipher_get(session) != GNUTLS_CIPHER_CHACHA20_POLY1305)) { + return GNUTLS_E_UNIMPLEMENTED_FEATURE; + } + +@@ -114,7 +116,7 @@ int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable + case GNUTLS_CIPHER_AES_128_GCM: + { + struct tls12_crypto_info_aes_gcm_128 crypto_info; +- memset(&crypto_info, 0, sizeof(crypto_info)); ++ memset(&crypto_info, 0, sizeof (crypto_info)); + + crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_128; + assert(cipher_key.size == TLS_CIPHER_AES_GCM_128_KEY_SIZE); +@@ -150,7 +152,7 @@ int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable + case GNUTLS_CIPHER_AES_256_GCM: + { + struct tls12_crypto_info_aes_gcm_256 crypto_info; +- memset(&crypto_info, 0, sizeof(crypto_info)); ++ memset(&crypto_info, 0, sizeof (crypto_info)); + + crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_256; + assert (cipher_key.size == TLS_CIPHER_AES_GCM_256_KEY_SIZE); +@@ -182,9 +184,83 @@ int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable + } + } + break; ++ case GNUTLS_CIPHER_AES_128_CCM: ++ { ++ struct tls12_crypto_info_aes_ccm_128 crypto_info; ++ memset(&crypto_info, 0, sizeof (crypto_info)); ++ ++ crypto_info.info.cipher_type = TLS_CIPHER_AES_CCM_128; ++ assert(cipher_key.size == TLS_CIPHER_AES_CCM_128_KEY_SIZE); ++ ++ /* for TLS 1.2 IV is generated in kernel */ ++ if (version == GNUTLS_TLS1_2) { ++ crypto_info.info.version = TLS_1_2_VERSION; ++ memcpy(crypto_info.iv, seq_number, TLS_CIPHER_AES_CCM_128_IV_SIZE); ++ } else { ++ crypto_info.info.version = TLS_1_3_VERSION; ++ assert(iv.size == TLS_CIPHER_AES_CCM_128_SALT_SIZE ++ + TLS_CIPHER_AES_CCM_128_IV_SIZE); ++ ++ memcpy(crypto_info.iv, iv.data + ++ TLS_CIPHER_AES_CCM_128_SALT_SIZE, ++ TLS_CIPHER_AES_CCM_128_IV_SIZE); ++ } ++ ++ memcpy(crypto_info.salt, iv.data, ++ TLS_CIPHER_AES_CCM_128_SALT_SIZE); ++ memcpy(crypto_info.rec_seq, seq_number, ++ TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE); ++ memcpy(crypto_info.key, cipher_key.data, ++ TLS_CIPHER_AES_CCM_128_KEY_SIZE); ++ ++ if (setsockopt (sockin, SOL_TLS, TLS_RX, ++ &crypto_info, sizeof (crypto_info))) { ++ session->internals.ktls_enabled &= ~GNUTLS_KTLS_RECV; ++ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ++ } ++ } ++ break; ++ case GNUTLS_CIPHER_CHACHA20_POLY1305: ++ { ++ struct tls12_crypto_info_chacha20_poly1305 crypto_info; ++ memset(&crypto_info, 0, sizeof (crypto_info)); ++ ++ crypto_info.info.cipher_type = TLS_CIPHER_CHACHA20_POLY1305; ++ assert(cipher_key.size == TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE); ++ ++ /* for TLS 1.2 IV is generated in kernel */ ++ if (version == GNUTLS_TLS1_2) { ++ crypto_info.info.version = TLS_1_2_VERSION; ++ memcpy(crypto_info.iv, seq_number, TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE); ++ } else { ++ crypto_info.info.version = TLS_1_3_VERSION; ++ assert(iv.size == TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE ++ + TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE); ++ ++ memcpy(crypto_info.iv, iv.data + ++ TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE, ++ TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE); ++ } ++ ++ memcpy(crypto_info.salt, iv.data, ++ TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE); ++ memcpy(crypto_info.rec_seq, seq_number, ++ TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE); ++ memcpy(crypto_info.key, cipher_key.data, ++ TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE); ++ ++ if (setsockopt (sockin, SOL_TLS, TLS_RX, ++ &crypto_info, sizeof (crypto_info))) { ++ session->internals.ktls_enabled &= ~GNUTLS_KTLS_RECV; ++ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ++ } ++ } ++ break; + default: + assert(0); + } ++ ++ + } + + ret = gnutls_record_get_state (session, 0, &mac_key, &iv, &cipher_key, +@@ -198,7 +274,7 @@ int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable + case GNUTLS_CIPHER_AES_128_GCM: + { + struct tls12_crypto_info_aes_gcm_128 crypto_info; +- memset(&crypto_info, 0, sizeof(crypto_info)); ++ memset(&crypto_info, 0, sizeof (crypto_info)); + + crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_128; + +@@ -234,7 +310,7 @@ int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable + case GNUTLS_CIPHER_AES_256_GCM: + { + struct tls12_crypto_info_aes_gcm_256 crypto_info; +- memset(&crypto_info, 0, sizeof(crypto_info)); ++ memset(&crypto_info, 0, sizeof (crypto_info)); + + crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_256; + assert (cipher_key.size == TLS_CIPHER_AES_GCM_256_KEY_SIZE); +@@ -266,10 +342,81 @@ int _gnutls_ktls_set_keys(gnutls_session_t session, gnutls_transport_ktls_enable + } + } + break; ++ case GNUTLS_CIPHER_AES_128_CCM: ++ { ++ struct tls12_crypto_info_aes_ccm_128 crypto_info; ++ memset(&crypto_info, 0, sizeof (crypto_info)); ++ ++ crypto_info.info.cipher_type = TLS_CIPHER_AES_CCM_128; ++ assert (cipher_key.size == TLS_CIPHER_AES_CCM_128_KEY_SIZE); ++ ++ /* for TLS 1.2 IV is generated in kernel */ ++ if (version == GNUTLS_TLS1_2) { ++ crypto_info.info.version = TLS_1_2_VERSION; ++ memcpy(crypto_info.iv, seq_number, TLS_CIPHER_AES_CCM_128_IV_SIZE); ++ } else { ++ crypto_info.info.version = TLS_1_3_VERSION; ++ assert (iv.size == TLS_CIPHER_AES_CCM_128_SALT_SIZE + ++ TLS_CIPHER_AES_CCM_128_IV_SIZE); ++ ++ memcpy (crypto_info.iv, iv.data + TLS_CIPHER_AES_CCM_128_SALT_SIZE, ++ TLS_CIPHER_AES_CCM_128_IV_SIZE); ++ } ++ ++ memcpy (crypto_info.salt, iv.data, ++ TLS_CIPHER_AES_CCM_128_SALT_SIZE); ++ memcpy (crypto_info.rec_seq, seq_number, ++ TLS_CIPHER_AES_CCM_128_REC_SEQ_SIZE); ++ memcpy (crypto_info.key, cipher_key.data, ++ TLS_CIPHER_AES_CCM_128_KEY_SIZE); ++ ++ if (setsockopt (sockout, SOL_TLS, TLS_TX, ++ &crypto_info, sizeof (crypto_info))) { ++ session->internals.ktls_enabled &= ~GNUTLS_KTLS_SEND; ++ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ++ } ++ } ++ break; ++ case GNUTLS_CIPHER_CHACHA20_POLY1305: ++ { ++ struct tls12_crypto_info_chacha20_poly1305 crypto_info; ++ memset(&crypto_info, 0, sizeof (crypto_info)); ++ ++ crypto_info.info.cipher_type = TLS_CIPHER_CHACHA20_POLY1305; ++ assert (cipher_key.size == TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE); ++ ++ /* for TLS 1.2 IV is generated in kernel */ ++ if (version == GNUTLS_TLS1_2) { ++ crypto_info.info.version = TLS_1_2_VERSION; ++ memcpy(crypto_info.iv, seq_number, TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE); ++ } else { ++ crypto_info.info.version = TLS_1_3_VERSION; ++ assert (iv.size == TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE + ++ TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE); ++ ++ memcpy (crypto_info.iv, iv.data + TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE, ++ TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE); ++ } ++ ++ memcpy (crypto_info.salt, iv.data, ++ TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE); ++ memcpy (crypto_info.rec_seq, seq_number, ++ TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE); ++ memcpy (crypto_info.key, cipher_key.data, ++ TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE); ++ ++ if (setsockopt (sockout, SOL_TLS, TLS_TX, ++ &crypto_info, sizeof (crypto_info))) { ++ session->internals.ktls_enabled &= ~GNUTLS_KTLS_SEND; ++ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); ++ } ++ } ++ break; + default: + assert(0); + } + ++ + // set callback for sending handshake messages + gnutls_handshake_set_read_function(session, + _gnutls_ktls_send_handshake_msg); +-- +2.38.1 + + +From 24bd0559302f8a7adf9f072f61f2aa03efa664f6 Mon Sep 17 00:00:00 2001 +From: Frantisek Krenzelok +Date: Fri, 2 Dec 2022 11:07:48 +0100 +Subject: [PATCH 2/2] KTLS: add ciphersuites (tests) + +Signed-off-by: Frantisek Krenzelok +--- + tests/gnutls_ktls.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/tests/gnutls_ktls.c b/tests/gnutls_ktls.c +index 8f9c5fa36..919270778 100644 +--- a/tests/gnutls_ktls.c ++++ b/tests/gnutls_ktls.c +@@ -350,8 +350,12 @@ void doit(void) + { + run("NORMAL:-VERS-ALL:+VERS-TLS1.2:-CIPHER-ALL:+AES-128-GCM"); + run("NORMAL:-VERS-ALL:+VERS-TLS1.2:-CIPHER-ALL:+AES-256-GCM"); ++ run("NORMAL:-VERS-ALL:+VERS-TLS1.2:-CIPHER-ALL:+AES-128-CCM"); ++ run("NORMAL:-VERS-ALL:+VERS-TLS1.2:-CIPHER-ALL:+CHACHA20-POLY1305"); + run("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM"); + run("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-256-GCM"); ++ run("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-CCM"); ++ run("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+CHACHA20-POLY1305"); + } + + #endif /* _WIN32 */ +-- +2.38.1 + diff --git a/gnutls-3.7.8-ktls_invalidate_session.patch b/gnutls-3.7.8-ktls_invalidate_session.patch new file mode 100644 index 0000000..aaa4793 --- /dev/null +++ b/gnutls-3.7.8-ktls_invalidate_session.patch @@ -0,0 +1,62 @@ +From 9533fcbacdb5532425568e3874cfea9f0a9b55d5 Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Mon, 28 Nov 2022 11:10:58 +0900 +Subject: [PATCH 1/2] src: fix memory leak in print_rawpk_info + +Signed-off-by: Daiki Ueno +--- + src/common.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/common.c b/src/common.c +index 6d2056f95..20327b41c 100644 +--- a/src/common.c ++++ b/src/common.c +@@ -222,7 +222,7 @@ print_rawpk_info(gnutls_session_t session, FILE *out, int flag, int print_cert, + if (ret < 0) { + fprintf(stderr, "Encoding error: %s\n", + gnutls_strerror(ret)); +- return; ++ goto cleanup; + } + + log_msg(out, "\n%s\n", (char*)pem.data); +@@ -230,6 +230,8 @@ print_rawpk_info(gnutls_session_t session, FILE *out, int flag, int print_cert, + gnutls_free(pem.data); + } + ++ cleanup: ++ gnutls_pcert_deinit(&pk_cert); + } + + /* returns false (0) if not verified, or true (1) otherwise +-- +2.38.1 + + +From ceac5211c073ba8dc86fe7cfb25504db33729fa9 Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Mon, 28 Nov 2022 11:14:53 +0900 +Subject: [PATCH 2/2] tests: fix memory leak in resume-with-previous-stek + +Signed-off-by: Daiki Ueno +--- + tests/resume-with-previous-stek.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tests/resume-with-previous-stek.c b/tests/resume-with-previous-stek.c +index 94f165627..98aba8d84 100644 +--- a/tests/resume-with-previous-stek.c ++++ b/tests/resume-with-previous-stek.c +@@ -127,6 +127,8 @@ static void client(int fd, int *resume, unsigned rounds, const char *prio) + + gnutls_deinit(session); + } ++ ++ gnutls_free(session_data.data); + } + + typedef void (* gnutls_stek_rotation_callback_t) (const gnutls_datum_t *prev_key, +-- +2.38.1 + diff --git a/gnutls-3.7.8-ktls_key_update.patch b/gnutls-3.7.8-ktls_key_update.patch new file mode 100644 index 0000000..5ca8a37 --- /dev/null +++ b/gnutls-3.7.8-ktls_key_update.patch @@ -0,0 +1,957 @@ +From c83b9ecbe8e7e5442867281236d8c9e1bd227204 Mon Sep 17 00:00:00 2001 +From: Frantisek Krenzelok +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +Date: Tue, 9 Aug 2022 12:11:16 +0200 +Subject: [PATCH 6/7] KTLS: rekey test + +Signed-off-by: Frantisek Krenzelok +--- + 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 ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 < "$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 +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 +--- + 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 + diff --git a/gnutls-3.7.8-ktls_minor_fixes.patch b/gnutls-3.7.8-ktls_minor_fixes.patch new file mode 100644 index 0000000..99749a1 --- /dev/null +++ b/gnutls-3.7.8-ktls_minor_fixes.patch @@ -0,0 +1,155 @@ +From ccf4463f343a9394a22833ee1de7886e459d3c91 Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Mon, 28 Nov 2022 12:17:12 +0900 +Subject: [PATCH 1/3] includes: move KTLS function definition out of + + + is meant for the functions that depend on +, which is not available on Windows platforms. + +As the KTLS API doesn't rely on , move the function and +enum to . + +Signed-off-by: Daiki Ueno +--- + lib/includes/gnutls/gnutls.h.in | 21 +++++++++++++++++++++ + lib/includes/gnutls/socket.h | 21 --------------------- + 2 files changed, 21 insertions(+), 21 deletions(-) + +diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in +index 394d465e3..830ce5f95 100644 +--- a/lib/includes/gnutls/gnutls.h.in ++++ b/lib/includes/gnutls/gnutls.h.in +@@ -3421,6 +3421,27 @@ int gnutls_fips140_pop_context(void); + + int gnutls_fips140_run_self_tests(void); + ++/** ++ * gnutls_transport_ktls_enable_flags_t: ++ * @GNUTLS_KTLS_RECV: ktls enabled for recv function. ++ * @GNUTLS_KTLS_SEND: ktls enabled for send function. ++ * @GNUTLS_KTLS_DUPLEX: ktls enabled for both recv and send functions. ++ * ++ * Flag enumeration of ktls enable status for recv and send functions. ++ * This is used by gnutls_transport_is_ktls_enabled(). ++ * ++ * Since: 3.7.3 ++ */ ++typedef enum { ++ GNUTLS_KTLS_RECV = 1 << 0, ++ GNUTLS_KTLS_SEND = 1 << 1, ++ GNUTLS_KTLS_DUPLEX = GNUTLS_KTLS_RECV | GNUTLS_KTLS_SEND, ++} gnutls_transport_ktls_enable_flags_t; ++ ++ ++gnutls_transport_ktls_enable_flags_t ++gnutls_transport_is_ktls_enabled(gnutls_session_t session); ++ + /* Gnutls error codes. The mapping to a TLS alert is also shown in + * comments. + */ +diff --git a/lib/includes/gnutls/socket.h b/lib/includes/gnutls/socket.h +index 4df7bb2e0..64eb19f89 100644 +--- a/lib/includes/gnutls/socket.h ++++ b/lib/includes/gnutls/socket.h +@@ -37,27 +37,6 @@ extern "C" { + #endif + /* *INDENT-ON* */ + +-/** +- * gnutls_transport_ktls_enable_flags_t: +- * @GNUTLS_KTLS_RECV: ktls enabled for recv function. +- * @GNUTLS_KTLS_SEND: ktls enabled for send function. +- * @GNUTLS_KTLS_DUPLEX: ktls enabled for both recv and send functions. +- * +- * Flag enumeration of ktls enable status for recv and send functions. +- * This is used by gnutls_transport_is_ktls_enabled(). +- * +- * Since: 3.7.3 +- */ +-typedef enum { +- GNUTLS_KTLS_RECV = 1 << 0, +- GNUTLS_KTLS_SEND = 1 << 1, +- GNUTLS_KTLS_DUPLEX = GNUTLS_KTLS_RECV | GNUTLS_KTLS_SEND, +-} gnutls_transport_ktls_enable_flags_t; +- +- +-gnutls_transport_ktls_enable_flags_t +-gnutls_transport_is_ktls_enabled(gnutls_session_t session); +- + void gnutls_transport_set_fastopen(gnutls_session_t session, + int fd, + struct sockaddr *connect_addr, +-- +2.38.1 + + +From 90b036e82a95f9379d99d5cabd0e33905d1e3ddc Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Mon, 28 Nov 2022 12:13:31 +0900 +Subject: [PATCH 2/3] src: print KTLS enablement status in + gnutls-serv/gnutls-cli + +Signed-off-by: Daiki Ueno +--- + src/common.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/src/common.c b/src/common.c +index 6d2056f95..d357c7fb8 100644 +--- a/src/common.c ++++ b/src/common.c +@@ -498,6 +498,7 @@ int print_info(gnutls_session_t session, int verbose, int flags) + gnutls_datum_t p; + char *desc; + gnutls_protocol_t version; ++ gnutls_transport_ktls_enable_flags_t ktls_flags; + int rc; + + desc = gnutls_session_get_desc(session); +@@ -646,6 +647,15 @@ int print_info(gnutls_session_t session, int verbose, int flags) + + print_channel_bindings(session, verbose); + ++ ktls_flags = gnutls_transport_is_ktls_enabled(session); ++ if (ktls_flags != 0) { ++ log_msg(stdout, "- KTLS: %s\n", ++ (ktls_flags & GNUTLS_KTLS_DUPLEX) == GNUTLS_KTLS_DUPLEX ? "send, recv" : ++ (ktls_flags & GNUTLS_KTLS_SEND) == GNUTLS_KTLS_SEND ? "send" : ++ (ktls_flags & GNUTLS_KTLS_RECV) == GNUTLS_KTLS_RECV ? "recv" : ++ "unknown"); ++ } ++ + fflush(stdout); + + return 0; +-- +2.38.1 + + +From aefd7319c0b7b2410d06238246b7755b289e4837 Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Mon, 28 Nov 2022 12:15:26 +0900 +Subject: [PATCH 3/3] priority: accept "ktls = false" in configuration file + +Signed-off-by: Daiki Ueno +--- + lib/priority.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/lib/priority.c b/lib/priority.c +index 97831e63b..6266bb571 100644 +--- a/lib/priority.c ++++ b/lib/priority.c +@@ -1548,6 +1548,8 @@ static int global_ini_handler(void *ctx, const char *section, const char *name, + p = clear_spaces(value, str); + if (c_strcasecmp(p, "true") == 0) { + cfg->ktls_enabled = true; ++ } else if (c_strcasecmp(p, "false") == 0) { ++ cfg->ktls_enabled = false; + } else { + _gnutls_debug_log("cfg: unknown ktls mode %s\n", + p); +-- +2.38.1 + diff --git a/gnutls.spec b/gnutls.spec index b515648..22040f8 100644 --- a/gnutls.spec +++ b/gnutls.spec @@ -20,8 +20,13 @@ print(string.sub(hash, 0, 16)) Version: 3.7.8 Release: %{?autorelease}%{!?autorelease:1%{?dist}} Patch: gnutls-3.7.8-gcc_analyzer-suppress_warnings.patch -Patch: gnutls-3.6.7-no-now-guile.patch Patch: gnutls-3.2.7-rpath.patch +Patch: gnutls-3.6.7-no-now-guile.patch + +Patch: gnutls-3.7.8-ktls_key_update.patch +Patch: gnutls-3.7.8-ktls_add_ciphersuites.patch +Patch: gnutls-3.7.8-ktls_minor_fixes.patch +Patch: gnutls-3.7.8-ktls_invalidate_session.patch %bcond_without bootstrap %bcond_without dane