[PATCH v2] tlshd: Send fatal alert to client when there are server config issues
Scott Mayhew <[email protected]>
| Newsgroups | dev.linux.lists.kernel-tls-handshake |
|---|---|
| Message-ID | <[email protected]> |
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 add some debug logging 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 <[email protected]>
---
src/tlshd/handshake.c | 4 ++++
src/tlshd/log.c | 15 ++++++++++++++
src/tlshd/server.c | 48 ++++++++++++++++++++++++++++---------------
src/tlshd/tlshd.h | 1 +
4 files changed, 51 insertions(+), 17 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
@@ -188,6 +188,21 @@ void tlshd_log_cert_verification_error(gnutls_session_t session)
tlshd_cert_status_names[i].name);
}
+/**
+ * @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));
+}
+
/**
* @brief Emit "library call failed" notification
* @param[in] error GnuTLS error code to log
diff --git a/src/tlshd/server.c b/src/tlshd/server.c
index 4850210..838c04b 100644
--- a/src/tlshd/server.c
+++ b/src/tlshd/server.c
@@ -397,30 +397,50 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm
gnutls_session_t session;
int ret;
+ ret = gnutls_init(&session, GNUTLS_SERVER);
+ if (ret != GNUTLS_E_SUCCESS) {
+ tlshd_log_gnutls_error(ret);
+ return;
+ }
+ gnutls_transport_set_int(session, parms->sockfd);
+ gnutls_session_set_ptr(session, parms);
+
+ ret = tlshd_gnutls_priority_set(session, parms, 0);
+ if (ret) {
+ tlshd_log_gnutls_error(ret);
+ gnutls_deinit(session);
+ return;
+ }
+
ret = gnutls_certificate_allocate_credentials(&xcred);
if (ret != GNUTLS_E_SUCCESS) {
tlshd_log_gnutls_error(ret);
+ gnutls_deinit(session);
return;
}
ret = tlshd_server_get_truststore(xcred);
- if (ret != GNUTLS_E_SUCCESS)
+ if (ret != GNUTLS_E_SUCCESS) {
+ tlshd_log_debug("Failed to initialize server trust store - check the configuration");
+ gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED);
+ gnutls_deinit(session);
goto out_free_creds;
+ }
- if (!tlshd_x509_server_get_certs(parms))
+ if (!tlshd_x509_server_get_certs(parms)) {
+ tlshd_log_debug("No usable server certificates were found - check the configuration");
+ gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED);
+ gnutls_deinit(session);
goto out_free_creds;
- if (!tlshd_x509_server_get_privkey(parms))
+ }
+ if (!tlshd_x509_server_get_privkey(parms)) {
+ tlshd_log_debug("No usable private keys were found - check the configuration");
+ gnutls_alert_send(session, GNUTLS_AL_FATAL, GNUTLS_A_ACCESS_DENIED);
+ gnutls_deinit(session);
goto out_free_certs;
+ }
gnutls_certificate_set_retrieve_function2(xcred,
tlshd_x509_retrieve_key_cb);
- ret = gnutls_init(&session, GNUTLS_SERVER);
- if (ret != GNUTLS_E_SUCCESS) {
- tlshd_log_gnutls_error(ret);
- goto out_free_certs;
- }
- gnutls_transport_set_int(session, parms->sockfd);
- gnutls_session_set_ptr(session, parms);
-
ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
if (ret != GNUTLS_E_SUCCESS) {
tlshd_log_gnutls_error(ret);
@@ -430,12 +450,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_free_certs;
- }
-
tlshd_start_tls_handshake(session, parms);
if (tlshd_debug &&
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