From c943e3e1a9a567c163d84c7ded449f1015c81d05 Mon Sep 17 00:00:00 2001 From: Scott Mayhew Date: Thu, 19 Feb 2026 12:53:33 -0500 Subject: [PATCH] tlshd: Send fatal alert to client when there are server config issues Resolves: RHEL-128086 Signed-off-by: Scott Mayhew --- ...p-logic-in-tlshd_start_tls_handshake.patch | 44 +++++ ...n-leak-on-error-paths-in-x509-server.patch | 57 ++++++ ...-alert-to-client-when-there-are-serv.patch | 185 ++++++++++++++++++ ktls-utils.spec | 6 + 4 files changed, 292 insertions(+) create mode 100644 ktls-utils-1.2.1-tlshd-Clean-up-logic-in-tlshd_start_tls_handshake.patch create mode 100644 ktls-utils-1.2.1-tlshd-Fix-session-leak-on-error-paths-in-x509-server.patch create mode 100644 ktls-utils-1.2.1-tlshd-Send-fatal-alert-to-client-when-there-are-serv.patch diff --git a/ktls-utils-1.2.1-tlshd-Clean-up-logic-in-tlshd_start_tls_handshake.patch b/ktls-utils-1.2.1-tlshd-Clean-up-logic-in-tlshd_start_tls_handshake.patch new file mode 100644 index 0000000..a5189ce --- /dev/null +++ b/ktls-utils-1.2.1-tlshd-Clean-up-logic-in-tlshd_start_tls_handshake.patch @@ -0,0 +1,44 @@ +From b52ca7c0a9c167340950a10d8dc56be1b95f5c40 Mon Sep 17 00:00:00 2001 +From: Chuck Lever +Date: Tue, 23 Sep 2025 19:30:16 -0400 +Subject: [PATCH] tlshd: Clean up logic in tlshd_start_tls_handshake() + +gnutls_handshake() is supposed to return only a GNUTLS_E value, and +the session_status field is supposed to contain only a positive +errno. + +GNUTLS_E_PREMATURE_TERMINATION is -110. It turns out that on x86, +-ETIMEDOUT is also -110. Make sure the correct symbolic constants +and auditing functions are utilized. + +Fixes: b010190cfed2 ("tlshd: Pass ETIMEDOUT from gnutls to kernel") +Reviewed-by: Benjamin Coddington +Signed-off-by: Chuck Lever +--- + src/tlshd/handshake.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/tlshd/handshake.c b/src/tlshd/handshake.c +index 5a28939..f688932 100644 +--- a/src/tlshd/handshake.c ++++ b/src/tlshd/handshake.c +@@ -97,12 +97,12 @@ void tlshd_start_tls_handshake(gnutls_session_t session, + case GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR: + tlshd_log_cert_verification_error(session); + break; +- case -ETIMEDOUT: +- tlshd_log_gnutls_error(ret); +- parms->session_status = -ret; ++ case GNUTLS_E_PREMATURE_TERMINATION: ++ tlshd_log_error("Handshake timeout, retrying"); ++ parms->session_status = ETIMEDOUT; + break; + default: +- tlshd_log_notice("tlshd_start_tls_handshake unhandled error %d, returning EACCES\n", ret); ++ tlshd_log_gnutls_error(ret); + } + return; + } +-- +2.52.0 + diff --git a/ktls-utils-1.2.1-tlshd-Fix-session-leak-on-error-paths-in-x509-server.patch b/ktls-utils-1.2.1-tlshd-Fix-session-leak-on-error-paths-in-x509-server.patch new file mode 100644 index 0000000..8e34ead --- /dev/null +++ b/ktls-utils-1.2.1-tlshd-Fix-session-leak-on-error-paths-in-x509-server.patch @@ -0,0 +1,57 @@ +From 9e79a86b85748ba4888da49652986b09beac2459 Mon Sep 17 00:00:00 2001 +From: Chuck Lever +Date: Thu, 5 Feb 2026 14:40:28 -0500 +Subject: [PATCH] tlshd: Fix session leak on error paths in x509 server + handshake + +Conflicts: src/tlshd/server.c - context difference in + tlshd_tls13_server_x509_handshake() because RHEL10 doesn't have + f11519a ("tlshd: Match ingress certificates with defined TLS session + tags") + +After gnutls_init() succeeds, the error paths for gnutls_credentials_set() +and tlshd_gnutls_priority_set() failures jump to out_free_certs without +calling gnutls_deinit(session), leaking the session object. + +Introduce an out_deinit_session label so all post-init error paths +properly release the session before cleaning up certificates and +credentials. + +Signed-off-by: Chuck Lever +--- + src/tlshd/server.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/tlshd/server.c b/src/tlshd/server.c +index 4850210..3bfcca3 100644 +--- a/src/tlshd/server.c ++++ b/src/tlshd/server.c +@@ -424,7 +424,7 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm + ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); + if (ret != GNUTLS_E_SUCCESS) { + tlshd_log_gnutls_error(ret); +- goto out_free_certs; ++ goto out_deinit_session; + } + gnutls_certificate_set_verify_function(xcred, + tlshd_tls13_server_x509_verify_function); +@@ -433,7 +433,7 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm + ret = tlshd_gnutls_priority_set(session, parms, 0); + if (ret) { + tlshd_log_gnutls_error(ret); +- goto out_free_certs; ++ goto out_deinit_session; + } + + tlshd_start_tls_handshake(session, parms); +@@ -373,6 +373,7 @@ static void tlshd_tls13_server_x509_hand + } + } + ++out_deinit_session: + gnutls_deinit(session); + + out_free_certs: +-- +2.52.0 + diff --git a/ktls-utils-1.2.1-tlshd-Send-fatal-alert-to-client-when-there-are-serv.patch b/ktls-utils-1.2.1-tlshd-Send-fatal-alert-to-client-when-there-are-serv.patch new file mode 100644 index 0000000..e23e4ad --- /dev/null +++ b/ktls-utils-1.2.1-tlshd-Send-fatal-alert-to-client-when-there-are-serv.patch @@ -0,0 +1,185 @@ +From a58a3600f35c16e435cdda476fe7ca0554a0a466 Mon Sep 17 00:00:00 2001 +From: Scott Mayhew +Date: Thu, 5 Feb 2026 12:28:43 -0500 +Subject: [PATCH] tlshd: Send fatal alert to client when there are server + config issues + +Conflicts: src/tlshd/log.c - context difference because RHEL10 doesn't + have ff28f1f ("tlshd: Translate kernel-style Doxygen comments in + src/tlshd/log.c") + +Currently if a client attempts an x.509 handshake and the server is +misconfigured (no certificates, no private keys, etc), the server simply +closes the connection. Prior to b010190 ("tlshd: Pass ETIMEDOUT from +gnutls to kernel"), this would result in a quick failure on the client. +Now the client keeps retrying until the mount program times out, which +takes several minutes. + +A misconfigured server isn't a self-correcting problem, so send a fatal +alert to the client when this occurs so the client stops retrying +immediately. This requires some minor refactoring of +tlshd_tls13_server_x509_handshake() so that the session is initialized +before attempting to load the certs and keys (otherwise it is not +possible to send an alert). Also log an error message to help the +admin take corrective action. + +Finally add some logging when an alert is received during the handshake. +Following suit with handshake completions, alerts will only be logged if +debug logging is enabled. + +Signed-off-by: Scott Mayhew +Signed-off-by: Chuck Lever +--- + src/tlshd/handshake.c | 4 ++++ + src/tlshd/log.c | 15 ++++++++++++ + src/tlshd/server.c | 55 ++++++++++++++++++++++++------------------- + src/tlshd/tlshd.h | 1 + + 4 files changed, 51 insertions(+), 24 deletions(-) + +diff --git a/src/tlshd/handshake.c b/src/tlshd/handshake.c +index e78f78f..511a369 100644 +--- a/src/tlshd/handshake.c ++++ b/src/tlshd/handshake.c +@@ -115,6 +115,10 @@ void tlshd_start_tls_handshake(gnutls_session_t session, + tlshd_log_error("Handshake timeout, retrying"); + parms->session_status = ETIMEDOUT; + break; ++ case GNUTLS_E_WARNING_ALERT_RECEIVED: ++ case GNUTLS_E_FATAL_ALERT_RECEIVED: ++ tlshd_log_alert(session); ++ break; + default: + tlshd_log_gnutls_error(ret); + } +diff --git a/src/tlshd/log.c b/src/tlshd/log.c +index b70d4af..a890b60 100644 +--- a/src/tlshd/log.c ++++ b/src/tlshd/log.c +@@ -178,6 +178,21 @@ void tlshd_log_cert_verification_error(g + } + + /** ++ * @brief Report a TLS alert ++ * @param[in] session Controlling GnuTLS session ++ */ ++void tlshd_log_alert(gnutls_session_t session) ++{ ++ gnutls_alert_description_t alert; ++ ++ if (!tlshd_debug) ++ return; ++ ++ alert = gnutls_alert_get(session); ++ tlshd_log_notice("Received alert: %s", gnutls_alert_get_name(alert)); ++} ++ ++/** + * tlshd_log_gnutls_error - Emit "library call failed" notification + * @error: GnuTLS error code to log + * +diff --git a/src/tlshd/server.c b/src/tlshd/server.c +index 3bfcca3..8e0f192 100644 +--- a/src/tlshd/server.c ++++ b/src/tlshd/server.c +@@ -397,29 +397,46 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm + gnutls_session_t session; + int ret; + +- ret = gnutls_certificate_allocate_credentials(&xcred); ++ ret = gnutls_init(&session, GNUTLS_SERVER); + if (ret != GNUTLS_E_SUCCESS) { + tlshd_log_gnutls_error(ret); + return; + } +- ret = tlshd_server_get_truststore(xcred); +- if (ret != GNUTLS_E_SUCCESS) +- goto out_free_creds; ++ gnutls_transport_set_int(session, parms->sockfd); ++ gnutls_session_set_ptr(session, parms); + +- if (!tlshd_x509_server_get_certs(parms)) +- goto out_free_creds; +- if (!tlshd_x509_server_get_privkey(parms)) +- goto out_free_certs; +- gnutls_certificate_set_retrieve_function2(xcred, +- tlshd_x509_retrieve_key_cb); ++ ret = tlshd_gnutls_priority_set(session, parms, 0); ++ if (ret) { ++ tlshd_log_gnutls_error(ret); ++ gnutls_deinit(session); ++ return; ++ } + +- ret = gnutls_init(&session, GNUTLS_SERVER); ++ ret = gnutls_certificate_allocate_credentials(&xcred); + if (ret != GNUTLS_E_SUCCESS) { + tlshd_log_gnutls_error(ret); +- goto out_free_certs; ++ gnutls_deinit(session); ++ return; + } +- gnutls_transport_set_int(session, parms->sockfd); +- gnutls_session_set_ptr(session, parms); ++ ret = tlshd_server_get_truststore(xcred); ++ if (ret != GNUTLS_E_SUCCESS) { ++ tlshd_log_error("Failed to initialize server trust store - check the configuration"); ++ gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED); ++ goto out_deinit_session; ++ } ++ ++ if (!tlshd_x509_server_get_certs(parms)) { ++ tlshd_log_error("No usable server certificates were found - check the configuration"); ++ gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED); ++ goto out_deinit_session; ++ } ++ if (!tlshd_x509_server_get_privkey(parms)) { ++ tlshd_log_error("No usable private keys were found - check the configuration"); ++ gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED); ++ goto out_deinit_session; ++ } ++ gnutls_certificate_set_retrieve_function2(xcred, ++ tlshd_x509_retrieve_key_cb); + + ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); + if (ret != GNUTLS_E_SUCCESS) { +@@ -430,12 +447,6 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm + tlshd_tls13_server_x509_verify_function); + gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUEST); + +- ret = tlshd_gnutls_priority_set(session, parms, 0); +- if (ret) { +- tlshd_log_gnutls_error(ret); +- goto out_deinit_session; +- } +- + tlshd_start_tls_handshake(session, parms); + + if (tlshd_debug && +@@ -464,12 +475,8 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm + + out_deinit_session: + gnutls_deinit(session); +- +-out_free_certs: + tlshd_x509_server_put_privkey(); + tlshd_x509_server_put_certs(); +- +-out_free_creds: + gnutls_certificate_free_credentials(xcred); + } + +diff --git a/src/tlshd/tlshd.h b/src/tlshd/tlshd.h +index 75d9a4a..d00cfdf 100644 +--- a/src/tlshd/tlshd.h ++++ b/src/tlshd/tlshd.h +@@ -118,6 +118,7 @@ extern void tlshd_log_perror(const char *prefix); + extern void tlshd_log_gai_error(int error); + + extern void tlshd_log_cert_verification_error(gnutls_session_t session); ++extern void tlshd_log_alert(gnutls_session_t session); + extern void tlshd_log_gnutls_error(int error); + extern void tlshd_gnutls_log_func(int level, const char *msg); + extern void tlshd_gnutls_audit_func(gnutls_session_t session, const char *msg); +-- +2.52.0 + diff --git a/ktls-utils.spec b/ktls-utils.spec index 7ebbc83..73ff333 100644 --- a/ktls-utils.spec +++ b/ktls-utils.spec @@ -16,10 +16,16 @@ URL: %{forgeurl} # FIXME: is this a bug in the tagging scheme or forgesource macro? Source0: %{forgeurl}/releases/download/%{name}-%{baseversion}/%{name}-%{baseversion}.tar.gz +# +# RHEL10.2 +# Patch0: ktls-utils-1.2.1-tlshd-deduplicate-client-and-server-config-functions.patch Patch1: ktls-utils-1.2.1-tlshd-Fix-priority-string-to-allow-PQC.patch Patch2: ktls-utils-1.2.1-tlshd-Server-side-dual-certificate-support.patch Patch3: ktls-utils-1.2.1-tlshd-Client-side-dual-certificate-support.patch +Patch4: ktls-utils-1.2.1-tlshd-Clean-up-logic-in-tlshd_start_tls_handshake.patch +Patch5: ktls-utils-1.2.1-tlshd-Fix-session-leak-on-error-paths-in-x509-server.patch +Patch6: ktls-utils-1.2.1-tlshd-Send-fatal-alert-to-client-when-there-are-serv.patch BuildRequires: bash systemd-rpm-macros BuildRequires: gcc make coreutils