From ececf27ed00e5f8e85923d2ce51f52818443a305 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 17 Jul 2025 22:40:03 +0200 Subject: [PATCH] Revert "tlshd: Do not return remote peer IDs for x.509 handshakes" This reverts commit d507771d618bbb2d264af20d2305803ea9bf368e, which seems to break mTLS. The symptoms for NFS are that a mount seems to succeed but then all operations on the client return EPERM. Use g_array_append_val() to store the peer IDs, as is done in in the PSK callback functions. Signed-off-by: Ben Hutchings --- src/tlshd/client.c | 29 ++++++++++++++++++++++++++++- src/tlshd/server.c | 31 +++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/tlshd/client.c b/src/tlshd/client.c index 0e648ed..7da8004 100644 --- a/src/tlshd/client.c +++ b/src/tlshd/client.c @@ -235,7 +235,8 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session, static int tlshd_client_x509_verify_function(gnutls_session_t session, struct tlshd_handshake_parms *parms) { - unsigned int status; + const gnutls_datum_t *peercerts; + unsigned int i, status, num_peercerts; int ret; ret = gnutls_certificate_verify_peers3(session, parms->peername, @@ -251,6 +252,32 @@ static int tlshd_client_x509_verify_function(gnutls_session_t session, * to get picky. Kernel would have to tell us what to look for * via a netlink attribute. */ + peercerts = gnutls_certificate_get_peers(session, &num_peercerts); + if (!peercerts || num_peercerts == 0) { + tlshd_log_debug("The peer cert list is empty.\n"); + return GNUTLS_E_CERTIFICATE_ERROR; + } + + tlshd_log_debug("The peer offered %u certificate(s).\n", + num_peercerts); + + for (i = 0; i < num_peercerts; i++) { + gnutls_x509_crt_t cert; + key_serial_t peerid; + + gnutls_x509_crt_init(&cert); + ret = gnutls_x509_crt_import(cert, &peercerts[i], + GNUTLS_X509_FMT_DER); + if (ret != GNUTLS_E_SUCCESS) { + tlshd_log_gnutls_error(ret); + gnutls_x509_crt_deinit(cert); + return GNUTLS_E_CERTIFICATE_ERROR; + } + peerid = tlshd_keyring_create_cert(cert, parms->peername); + g_array_append_val(parms->remote_peerids, peerid); + gnutls_x509_crt_deinit(cert); + } + return GNUTLS_E_SUCCESS; } diff --git a/src/tlshd/server.c b/src/tlshd/server.c index db5db31..ab022a3 100644 --- a/src/tlshd/server.c +++ b/src/tlshd/server.c @@ -178,9 +178,10 @@ static int tlshd_server_get_truststore(gnutls_certificate_credentials_t cred) * verification failed. The server sends an ALERT to the client. */ static int tlshd_server_x509_verify_function(gnutls_session_t session, - __attribute__ ((unused)) struct tlshd_handshake_parms *parms) + struct tlshd_handshake_parms *parms) { - unsigned int status; + const gnutls_datum_t *peercerts; + unsigned int i, status, num_peercerts; int ret; ret = gnutls_certificate_verify_peers3(session, NULL, &status); @@ -201,6 +202,32 @@ static int tlshd_server_x509_verify_function(gnutls_session_t session, * to get picky. Kernel would have to tell us what to look for * via a netlink attribute. */ + peercerts = gnutls_certificate_get_peers(session, &num_peercerts); + if (!peercerts || num_peercerts == 0) { + tlshd_log_debug("The peer cert list is empty."); + goto certificate_error; + } + + tlshd_log_debug("The peer offered %u certificate(s).", + num_peercerts); + + for (i = 0; i < num_peercerts; i++) { + gnutls_x509_crt_t cert; + key_serial_t peerid; + + gnutls_x509_crt_init(&cert); + ret = gnutls_x509_crt_import(cert, &peercerts[i], + GNUTLS_X509_FMT_DER); + if (ret != GNUTLS_E_SUCCESS) { + tlshd_log_gnutls_error(ret); + gnutls_x509_crt_deinit(cert); + return GNUTLS_E_CERTIFICATE_ERROR; + } + peerid = tlshd_keyring_create_cert(cert, parms->peername); + g_array_append_val(parms->remote_peerids, peerid); + gnutls_x509_crt_deinit(cert); + } + return GNUTLS_E_SUCCESS; certificate_error: