From e4df37453e1978c44a72144e5e1d79d2242e9393 Mon Sep 17 00:00:00 2001 From: Frantisek Krenzelok Date: Thu, 8 Dec 2022 16:57:23 +0100 Subject: [PATCH] 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 --- gnutls-3.7.8-ktls-updates.patch | 620 ++++++++++++++++++++++++++++++++ gnutls.spec | 1 + 2 files changed, 621 insertions(+) create mode 100644 gnutls-3.7.8-ktls-updates.patch diff --git a/gnutls-3.7.8-ktls-updates.patch b/gnutls-3.7.8-ktls-updates.patch new file mode 100644 index 0000000..e34ae8f --- /dev/null +++ b/gnutls-3.7.8-ktls-updates.patch @@ -0,0 +1,620 @@ +diff -rpu a/lib/alert.c a/lib/alert.c +--- a/lib/alert.c 2022-12-09 14:58:19.713666537 +0100 ++++ a/lib/alert.c 2022-12-09 15:26:30.976250789 +0100 +@@ -182,15 +182,10 @@ gnutls_alert_send(gnutls_session_t sessi + 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 -rpu a/lib/handshake.c a/lib/handshake.c +--- a/lib/handshake.c 2022-12-09 14:58:19.712666534 +0100 ++++ a/lib/handshake.c 2022-12-09 15:31:51.768496850 +0100 +@@ -2924,7 +2924,13 @@ int gnutls_handshake(gnutls_session_t se + + #ifdef ENABLE_KTLS + if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_DUPLEX)) { +- _gnutls_ktls_set_keys(session); ++ ret = _gnutls_ktls_set_keys(session, GNUTLS_KTLS_DUPLEX); ++ if (ret < 0) { ++ /* no need to invalidate the session as keys were not set */ ++ session->internals.ktls_enabled = 0; ++ _gnutls_audit_log(session, ++ "disabling KTLS: failed to set keys\n"); ++ } + } + #endif + +diff -rpu a/lib/includes/gnutls/gnutls.h.in a/lib/includes/gnutls/gnutls.h.in +--- a/lib/includes/gnutls/gnutls.h.in 2022-12-09 14:58:19.706666511 +0100 ++++ a/lib/includes/gnutls/gnutls.h.in 2022-12-09 15:30:04.784082188 +0100 +@@ -3418,6 +3418,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 -rpu a/lib/includes/gnutls/socket.h a/lib/includes/gnutls/socket.h +--- a/lib/includes/gnutls/socket.h 2022-12-09 14:58:19.706666511 +0100 ++++ a/lib/includes/gnutls/socket.h 2022-12-09 15:30:04.785082192 +0100 +@@ -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, +diff -rpu a/lib/priority.c a/lib/priority.c +--- a/lib/priority.c 2022-12-09 14:58:19.712666534 +0100 ++++ a/lib/priority.c 2022-12-09 15:30:04.787082200 +0100 +@@ -1541,6 +1541,8 @@ static int global_ini_handler(void *ctx, + 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); +diff -rpu a/lib/record.c a/lib/record.c +--- a/lib/record.c 2022-12-09 14:58:19.712666534 +0100 ++++ a/lib/record.c 2022-12-09 15:26:30.978250796 +0100 +@@ -2065,11 +2065,17 @@ gnutls_record_send2(gnutls_session_t ses + 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 + 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 -rpu a/lib/system/ktls.c a/lib/system/ktls.c +--- a/lib/system/ktls.c 2022-12-09 14:58:19.710666526 +0100 ++++ a/lib/system/ktls.c 2022-12-09 15:31:31.358417745 +0100 +@@ -80,13 +80,13 @@ void _gnutls_ktls_enable(gnutls_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; + 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 + 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; + } + +@@ -107,12 +109,14 @@ int _gnutls_ktls_set_keys(gnutls_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: + { + 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); +@@ -148,7 +152,7 @@ int _gnutls_ktls_set_keys(gnutls_session + 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); +@@ -180,9 +184,83 @@ int _gnutls_ktls_set_keys(gnutls_session + } + } + 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, +@@ -191,12 +269,12 @@ int _gnutls_ktls_set_keys(gnutls_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: + { + 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; + +@@ -232,7 +310,7 @@ int _gnutls_ktls_set_keys(gnutls_session + 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); +@@ -264,12 +342,90 @@ int _gnutls_ktls_set_keys(gnutls_session + } + } + 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); ++ ++ // set callback for sending alert messages ++ gnutls_alert_set_read_function(session, _gnutls_ktls_send_alert_msg); + } + +- return 0; ++ return in; + } + + ssize_t _gnutls_ktls_send_file(gnutls_session_t session, int fd, +@@ -353,6 +509,26 @@ int _gnutls_ktls_send_control_msg(gnutls + 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_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) + { +@@ -438,7 +614,13 @@ int _gnutls_ktls_recv_int(gnutls_session + 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; +@@ -465,7 +647,7 @@ gnutls_transport_is_ktls_enabled(gnutls_ + 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); + } + +@@ -479,6 +661,15 @@ int _gnutls_ktls_send_control_msg(gnutls + 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 -rpu a/lib/system/ktls.h a/lib/system/ktls.h +--- a/lib/system/ktls.h 2022-12-09 14:58:19.710666526 +0100 ++++ a/lib/system/ktls.h 2022-12-09 15:26:30.979250800 +0100 +@@ -4,14 +4,29 @@ + #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_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_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); ++ + 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) + +diff -rpu a/lib/tls13/key_update.c a/lib/tls13/key_update.c +--- a/lib/tls13/key_update.c 2022-12-09 14:58:19.711666530 +0100 ++++ a/lib/tls13/key_update.c 2022-12-09 15:31:51.769496854 +0100 +@@ -27,10 +27,28 @@ + #include "mem.h" + #include "mbuffers.h" + #include "secrets.h" ++#include "system/ktls.h" + + #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;\ ++ session->internals.invalid_connection = true;\ ++ session->internals.resumable = false;\ ++ _gnutls_audit_log(session,\ ++ "invalidating session: KTLS - couldn't update keys\n");\ ++ ret = GNUTLS_E_INTERNAL_ERROR;\ ++}\ ++} ++ + static int update_keys(gnutls_session_t session, hs_stage_t stage) + { + int ret; +@@ -49,8 +67,20 @@ static int update_keys(gnutls_session_t + * write keys */ + if (session->internals.recv_state == RECV_STATE_EARLY_START) { + ret = _tls13_write_connection_state_init(session, stage); ++ if (ret < 0) ++ return gnutls_assert_val(ret); ++ ++ if (IS_KTLS_ENABLED(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) ++ SET_KTLS_KEYS(session, GNUTLS_KTLS_SEND) ++ else if (IS_KTLS_ENABLED(session, GNUTLS_KTLS_RECV) && stage == STAGE_UPD_PEERS) ++ SET_KTLS_KEYS(session, GNUTLS_KTLS_RECV) + } + if (ret < 0) + return gnutls_assert_val(ret); +diff -rpu a/src/common.c a/src/common.c +--- a/src/common.c 2022-12-09 14:58:19.737666626 +0100 ++++ a/src/common.c 2022-12-09 15:30:04.788082204 +0100 +@@ -498,6 +498,7 @@ int print_info(gnutls_session_t session, + 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, + + 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; +diff -rpu a/tests/gnutls_ktls.c a/tests/gnutls_ktls.c +--- a/tests/gnutls_ktls.c 2022-12-09 14:58:19.751666678 +0100 ++++ a/tests/gnutls_ktls.c 2022-12-09 15:31:31.359417748 +0100 +@@ -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 */ +diff -rpu a/tests/Makefile.am a/tests/Makefile.am +--- a/tests/Makefile.am 2022-12-09 14:58:19.748666667 +0100 ++++ a/tests/Makefile.am 2022-12-09 15:26:30.979250800 +0100 +@@ -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/gnutls.spec b/gnutls.spec index b515648..d759681 100644 --- a/gnutls.spec +++ b/gnutls.spec @@ -19,6 +19,7 @@ print(string.sub(hash, 0, 16)) Version: 3.7.8 Release: %{?autorelease}%{!?autorelease:1%{?dist}} +Patch: gnutls-3.7.8-ktls-updates.patch 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