From: Alistair Francis Date: Mon, 26 May 2025 04:41:46 +0000 (+1000) Subject: tls13/key_update: Expose a manual KeyUpdate function X-Git-Tag: 3.8.11~12^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=68077482f5a72ef8176b3f9edf9b63f1663a9ae8;p=thirdparty%2Fgnutls.git tls13/key_update: Expose a manual KeyUpdate function As part of supporting KeyUpdate in ktls-utils and NVMe-OF we need to trigger an update of the local keys after the kernel has received a KeyUpdate message. This patch creates a new gnutls_handshake_update_receiving_key() function that allows updating the local keys without sending any KeyUpdate requests. Signed-off-by: Alistair Francis Modified-by: Daiki Ueno --- diff --git a/NEWS b/NEWS index f2457db51f..648206d805 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,11 @@ See the end for copying conditions. A new function gnutls_record_get_max_send_size() has been added to determine the maximum size of a TLS record to be sent to the peer. +** libgnutls: Expose a new function to update keys without sending a KeyUpdate + to the peer. A new function gnutls_handshake_update_receiving_key() + has been added to allow updating the local receiving key without + sending any KeyUpdate messages. + ** libgnutls: PKCS#11 cryptographic provider configuration takes a token URI instead of a module path. To allow using a PKCS#11 module exposing multiple tokens, the "path" configuration keyword was replaced with @@ -26,6 +31,7 @@ See the end for copying conditions. gnutls_psk_allocate_client_credentials2: New function gnutls_psk_allocate_server_credentials2: New function gnutls_record_get_max_send_size: New function +gnutls_handshake_update_receiving_key: New function * Version 3.8.10 (released 2025-07-08) diff --git a/devel/symbols.last b/devel/symbols.last index 7cdfc8c3e7..25084c13c6 100644 --- a/devel/symbols.last +++ b/devel/symbols.last @@ -22,6 +22,7 @@ GNUTLS_3_8_1@GNUTLS_3_8_1 GNUTLS_3_8_2@GNUTLS_3_8_2 GNUTLS_3_8_4@GNUTLS_3_8_4 GNUTLS_3_8_6@GNUTLS_3_8_6 +GNUTLS_3_8_10@GNUTLS_3_8_10 _gnutls_global_init_skip@GNUTLS_3_4 gnutls_aead_cipher_decrypt@GNUTLS_3_4 gnutls_aead_cipher_decryptv2@GNUTLS_3_6_10 @@ -832,6 +833,7 @@ gnutls_session_ticket_enable_client@GNUTLS_3_4 gnutls_session_ticket_enable_server@GNUTLS_3_4 gnutls_session_ticket_key_generate@GNUTLS_3_4 gnutls_session_ticket_send@GNUTLS_3_6_3 +gnutls_handshake_update_receiving_key@GNUTLS_3_8_6 gnutls_set_default_priority@GNUTLS_3_4 gnutls_set_default_priority_append@GNUTLS_3_6_3 gnutls_sign_algorithm_get@GNUTLS_3_4 diff --git a/doc/Makefile.am b/doc/Makefile.am index d697e66bdc..6b95ae255c 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1131,6 +1131,8 @@ FUNCS += functions/gnutls_handshake_set_secret_function FUNCS += functions/gnutls_handshake_set_secret_function.short FUNCS += functions/gnutls_handshake_set_timeout FUNCS += functions/gnutls_handshake_set_timeout.short +FUNCS += functions/gnutls_handshake_update_receiving_key +FUNCS += functions/gnutls_handshake_update_receiving_key.short FUNCS += functions/gnutls_handshake_write FUNCS += functions/gnutls_handshake_write.short FUNCS += functions/gnutls_hash diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am index eeca130abd..65a329ae14 100644 --- a/doc/manpages/Makefile.am +++ b/doc/manpages/Makefile.am @@ -411,6 +411,7 @@ APIMANS += gnutls_handshake_set_random.3 APIMANS += gnutls_handshake_set_read_function.3 APIMANS += gnutls_handshake_set_secret_function.3 APIMANS += gnutls_handshake_set_timeout.3 +APIMANS += gnutls_handshake_update_receiving_key.3 APIMANS += gnutls_handshake_write.3 APIMANS += gnutls_hash.3 APIMANS += gnutls_hash_copy.3 diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index d14cd4bf43..781c9be4c2 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -1330,6 +1330,8 @@ int gnutls_rehandshake(gnutls_session_t session); #define GNUTLS_KU_PEER 1 int gnutls_session_key_update(gnutls_session_t session, unsigned flags); +int gnutls_handshake_update_receiving_key(gnutls_session_t session); + gnutls_alert_description_t gnutls_alert_get(gnutls_session_t session); int gnutls_alert_send(gnutls_session_t session, gnutls_alert_level_t level, gnutls_alert_description_t desc); diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 2d86a1e14a..2ae72e5477 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1456,6 +1456,7 @@ GNUTLS_3_8_11 gnutls_psk_allocate_client_credentials2; gnutls_psk_allocate_server_credentials2; gnutls_record_get_max_send_size; + gnutls_handshake_update_receiving_key; local: *; } GNUTLS_3_8_6; diff --git a/lib/tls13/key_update.c b/lib/tls13/key_update.c index beee1dc41a..f7fe13a945 100644 --- a/lib/tls13/key_update.c +++ b/lib/tls13/key_update.c @@ -274,3 +274,42 @@ int gnutls_session_key_update(gnutls_session_t session, unsigned flags) return 0; } + +/** + * gnutls_handshake_update_receiving_key: + * @session: is a #gnutls_session_t type. + * + * This function will update/refresh the session receiving keys when + * the TLS protocol is 1.3 or better. Unlike gnutls_session_key_update() + * this function does not notify the peer, it will only update + * the local keys. + * + * If the negotiated version is not TLS 1.3 or better this + * function will return %GNUTLS_E_INVALID_REQUEST. + * + * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code. + * + * Since: 3.8.11 + **/ +int gnutls_handshake_update_receiving_key(gnutls_session_t session) +{ + int ret; + const version_entry_st *vers = get_version(session); + + if (!vers->tls13_sem) + return GNUTLS_E_INVALID_REQUEST; + + _gnutls_epoch_gc(session); + + ret = _tls13_update_secret(session, + session->key.proto.tls13.temp_secret, + session->key.proto.tls13.temp_secret_size); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = update_receiving_key(session, STAGE_UPD_PEERS); + if (ret < 0) + return gnutls_assert_val(ret); + + return 0; +} diff --git a/lib/tls13/key_update.h b/lib/tls13/key_update.h index 326af381bc..9e7040bf97 100644 --- a/lib/tls13/key_update.h +++ b/lib/tls13/key_update.h @@ -23,6 +23,8 @@ #ifndef GNUTLS_LIB_TLS13_KEY_UPDATE_H #define GNUTLS_LIB_TLS13_KEY_UPDATE_H +int gnutls_handshake_update_receiving_key(gnutls_session_t session); + int _gnutls13_recv_key_update(gnutls_session_t session, gnutls_buffer_st *buf); int _gnutls13_send_key_update(gnutls_session_t session, unsigned again, unsigned flags); diff --git a/tests/handshake-write.c b/tests/handshake-write.c index 1cecb06993..600cebf8d0 100644 --- a/tests/handshake-write.c +++ b/tests/handshake-write.c @@ -73,6 +73,9 @@ static int handshake_read_func(gnutls_session_t session, if (htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC) return 0; + if (htype == GNUTLS_HANDSHAKE_KEY_UPDATE) + return 0; + return gnutls_handshake_write(peer, level, data, data_size); } @@ -144,6 +147,17 @@ static void run(const char *name, const char *prio) TRANSFER(client, server, MSG, strlen(MSG), buffer, MAX_BUF); TRANSFER(server, client, MSG, strlen(MSG), buffer, MAX_BUF); + /* Trigger a KeyUpdate that won't actually be sent to the client, + * as handshake_read_func() will drop the message. + */ + gnutls_session_key_update(server, GNUTLS_KU_PEER); + + /* Manually update the client keys */ + gnutls_handshake_update_receiving_key(client); + + TRANSFER(client, server, MSG, strlen(MSG), buffer, MAX_BUF); + TRANSFER(server, client, MSG, strlen(MSG), buffer, MAX_BUF); + gnutls_bye(client, GNUTLS_SHUT_WR); gnutls_bye(server, GNUTLS_SHUT_WR);