Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
78e91a7
tlshd: Fix a minor race
chucklever Jun 2, 2025
dbdedcc
tlshd: Remove unneeded variable "error"
chucklever Jun 2, 2025
3ff8a36
workflows: Limit permission of the makefile.yml action
chucklever Jun 2, 2025
96340c1
tlshd: Add default keyrings for NFS
chucklever Jun 5, 2025
69b6a54
tlshd: Relocate TLSHD_ALLPERMS
chucklever Jun 7, 2025
731d1b2
tlshd: Handshake needs to check for CERTIFICATE_ERROR
chucklever Jun 16, 2025
67ef5a5
tlshd: Fix silent tlshd_keyring_link_session() failures
chucklever Jun 14, 2025
46d9e84
tlshd: Don't set errno in tlshd_keyring_link_session()
chucklever Jun 14, 2025
cc49670
tlshd: Display errno message
chucklever Jun 14, 2025
d3d5c3a
tlshd: Check for an empty string
chucklever Jun 14, 2025
058f257
tlshd: Show ingress certificate on successful handshake
chucklever Jun 11, 2025
1177c26
tlshd: Remove useless verification status report
chucklever Jun 16, 2025
a6eec63
tlshd: Do not return remote peer IDs for x.509 handshakes
chucklever Jun 16, 2025
9e85767
tlshd: Add tlshd_log_completion()
chucklever Jun 14, 2025
5c5b730
tlshd: Restore GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR
chucklever Jun 21, 2025
ccd22a5
tlshd: Preserve pcache during tlshd_gnutls_priority_init()
chucklever Jun 27, 2025
9844627
tlshd: Release server certs and priv key
chucklever Jun 27, 2025
93ed465
tlshd: Release client cert and priv key
chucklever Jun 28, 2025
b910855
tlshd: Free netlink messages after fork(3) returns
chucklever Jun 27, 2025
c3f3e2d
tlshd: Child process should shut down before exiting
chucklever Jun 28, 2025
1a95de5
tlshd: Child should close the notification socket
chucklever Jun 28, 2025
65dffd5
tlshd: Add a SIGINT handler
chucklever Jun 28, 2025
2fbaf34
tlshd: Refactor trust store management
chucklever Jun 18, 2025
cb8470d
tlshd: Add server-side CRL checking
rtheys Jun 18, 2025
7519860
Add client-side CRL checking
rtheys Jun 18, 2025
d0ffb5f
tlshd: Add x509.crl option to man page.
rtheys Jun 18, 2025
b967c32
tlshd: Add tlshd_genl_put_handshake_parms() API
chucklever Jun 13, 2025
1e03c0e
tlshd: Store remote peerids in a GArray
chucklever Jun 14, 2025
86607af
tlshd: Store peer IDs in a GArray
chucklever Jun 14, 2025
484b63c
tlshd: Convert parms->peeraddr to a presentation address
chucklever Jun 16, 2025
808a57f
tlshd: Dynamically allocate hostname
chucklever Jun 16, 2025
964aaf0
Release ktls-utils 1.2.0
chucklever Jul 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/makefile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ jobs:
build:

runs-on: ubuntu-latest
permissions: read-all
strategy:
fail-fast: false
matrix:
Expand Down
6 changes: 6 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
Change Log - In newest-release-first order

ktls-utils 1.2.0 2025-07-11
* Implement Certificate Revocation Lists
* Add a default keyring for NFS consumers
* Improvements to error reporting and logging
* Manage per-session resources more effectively

ktls-utils 1.1.0 2025-06-02
* Return to the old release process
* Update the contribution process
Expand Down
10 changes: 5 additions & 5 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
ktls-utils 1.1.0 2025-06-02
* Return to the old release process
* Update the contribution process
* Accept alternate keyrings during handshake upcall
* Initial support for building ktls-utils with MUSL
ktls-utils 1.2.0 2025-07-11
* Implement Certificate Revocation Lists
* Add a default keyring for NFS consumers
* Improvements to error reporting and logging
* Manage per-session resources more effectively
2 changes: 1 addition & 1 deletion README
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Release Notes for ktls-utils 1.1.0
# Release Notes for ktls-utils 1.2.0

In-kernel TLS consumers need a mechanism to perform TLS handshakes
on a connected socket to negotiate TLS session parameters that can
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Release Notes for ktls-utils 1.1.0
# Release Notes for ktls-utils 1.2.0

In-kernel TLS consumers need a mechanism to perform TLS handshakes
on a connected socket to negotiate TLS session parameters that can
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ dnl 02110-1301, USA.
dnl

AC_PREREQ([2.69])
AC_INIT([ktls-utils],[1.1.0],[[email protected]])
AC_INIT([ktls-utils],[1.2.0],[[email protected]])
AM_INIT_AUTOMAKE
AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR([config.h.in])
Expand Down
157 changes: 70 additions & 87 deletions src/tlshd/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,42 @@
#include "tlshd.h"
#include "netlink.h"

static int tlshd_client_get_truststore(gnutls_certificate_credentials_t cred)
{
char *pathname;
int ret;

if (tlshd_config_get_client_truststore(&pathname)) {
ret = gnutls_certificate_set_x509_trust_file(cred, pathname,
GNUTLS_X509_FMT_PEM);
free(pathname);
} else
ret = gnutls_certificate_set_x509_system_trust(cred);
if (ret < 0) {
tlshd_log_gnutls_error(ret);
return ret;
}
tlshd_log_debug("System trust: Loaded %d certificate(s).", ret);

if (tlshd_config_get_client_crl(&pathname)) {
ret = gnutls_certificate_set_x509_crl_file(cred, pathname,
GNUTLS_X509_FMT_PEM);
free(pathname);
if (ret < 0 ) {
tlshd_log_gnutls_error(ret);
return ret;
}
tlshd_log_debug("System CRL: Loaded %d CRL(s).", ret);
}

return GNUTLS_E_SUCCESS;
}

static void tlshd_tls13_client_anon_handshake(struct tlshd_handshake_parms *parms)
{
gnutls_certificate_credentials_t xcred;
gnutls_session_t session;
unsigned int flags;
char *cafile;
int ret;

ret = gnutls_certificate_allocate_credentials(&xcred);
Expand All @@ -65,17 +95,9 @@ static void tlshd_tls13_client_anon_handshake(struct tlshd_handshake_parms *parm
gnutls_certificate_set_flags(xcred,
GNUTLS_CERTIFICATE_SKIP_KEY_CERT_MATCH | GNUTLS_CERTIFICATE_SKIP_OCSP_RESPONSE_CHECK);

if (tlshd_config_get_client_truststore(&cafile)) {
ret = gnutls_certificate_set_x509_trust_file(xcred, cafile,
GNUTLS_X509_FMT_PEM);
free(cafile);
} else
ret = gnutls_certificate_set_x509_system_trust(xcred);
if (ret < 0) {
tlshd_log_gnutls_error(ret);
ret = tlshd_client_get_truststore(xcred);
if (ret != GNUTLS_E_SUCCESS)
goto out_free_creds;
}
tlshd_log_debug("System trust: Loaded %d certificate(s).", ret);

flags = GNUTLS_CLIENT;
ret = gnutls_init(&session, flags);
Expand Down Expand Up @@ -116,9 +138,6 @@ static gnutls_privkey_t tlshd_privkey;
static unsigned int tlshd_certs_len = TLSHD_MAX_CERTS;
static gnutls_pcert_st tlshd_certs[TLSHD_MAX_CERTS];

/*
* XXX: After this point, tlshd_certs should be deinited on error.
*/
static bool tlshd_x509_client_get_certs(struct tlshd_handshake_parms *parms)
{
if (parms->x509_cert != TLS_NO_CERT)
Expand All @@ -127,9 +146,14 @@ static bool tlshd_x509_client_get_certs(struct tlshd_handshake_parms *parms)
return tlshd_config_get_client_certs(tlshd_certs, &tlshd_certs_len);
}

/*
* XXX: After this point, tlshd_privkey should be deinited on error.
*/
static void tlshd_x509_client_put_certs(void)
{
unsigned int i;

for (i = 0; i < tlshd_certs_len; i++)
gnutls_pcert_deinit(&tlshd_certs[i]);
}

static bool tlshd_x509_client_get_privkey(struct tlshd_handshake_parms *parms)
{
if (parms->x509_privkey != TLS_NO_PRIVKEY)
Expand All @@ -138,6 +162,11 @@ static bool tlshd_x509_client_get_privkey(struct tlshd_handshake_parms *parms)
return tlshd_config_get_client_privkey(&tlshd_privkey);
}

static void tlshd_x509_client_put_privkey(void)
{
gnutls_privkey_deinit(tlshd_privkey);
}

static void tlshd_x509_log_issuers(const gnutls_datum_t *req_ca_rdn, int nreqs)
{
char issuer_dn[256];
Expand Down Expand Up @@ -206,10 +235,7 @@ 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)
{
const gnutls_datum_t *peercerts;
gnutls_certificate_type_t type;
unsigned int i, status;
gnutls_datum_t out;
unsigned int status;
int ret;

ret = gnutls_certificate_verify_peers3(session, parms->peername,
Expand All @@ -218,47 +244,13 @@ static int tlshd_client_x509_verify_function(gnutls_session_t session,
tlshd_log_gnutls_error(ret);
return GNUTLS_E_CERTIFICATE_ERROR;
}

type = gnutls_certificate_type_get(session);
gnutls_certificate_verification_status_print(status, type, &out, 0);
tlshd_log_debug("%s", out.data);
gnutls_free(out.data);

if (status)
return GNUTLS_E_CERTIFICATE_ERROR;

/* To do: Examine extended key usage information here, if we want
* to get picky. Kernel would have to tell us what to look for
* via a netlink attribute. */

peercerts = gnutls_certificate_get_peers(session,
&parms->num_remote_peerids);
if (!peercerts || parms->num_remote_peerids == 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",
parms->num_remote_peerids);

if (parms->num_remote_peerids > ARRAY_SIZE(parms->remote_peerid))
parms->num_remote_peerids = ARRAY_SIZE(parms->remote_peerid);
for (i = 0; i < parms->num_remote_peerids; i++) {
gnutls_x509_crt_t cert;

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;
}
parms->remote_peerid[i] =
tlshd_keyring_create_cert(cert, parms->peername);
gnutls_x509_crt_deinit(cert);
}

return GNUTLS_E_SUCCESS;
}

Expand All @@ -274,7 +266,6 @@ static void tlshd_tls13_client_x509_handshake(struct tlshd_handshake_parms *parm
gnutls_certificate_credentials_t xcred;
gnutls_session_t session;
unsigned int flags;
char *cafile;
int ret;

ret = gnutls_certificate_allocate_credentials(&xcred);
Expand All @@ -283,30 +274,22 @@ static void tlshd_tls13_client_x509_handshake(struct tlshd_handshake_parms *parm
return;
}

if (tlshd_config_get_client_truststore(&cafile)) {
ret = gnutls_certificate_set_x509_trust_file(xcred, cafile,
GNUTLS_X509_FMT_PEM);
free(cafile);
} else
ret = gnutls_certificate_set_x509_system_trust(xcred);
if (ret < 0) {
tlshd_log_gnutls_error(ret);
ret = tlshd_client_get_truststore(xcred);
if (ret != GNUTLS_E_SUCCESS)
goto out_free_creds;
}
tlshd_log_debug("System trust: Loaded %d certificate(s).", ret);

if (!tlshd_x509_client_get_certs(parms))
goto out_free_creds;
if (!tlshd_x509_client_get_privkey(parms))
goto out_free_creds;
goto out_free_certs;
gnutls_certificate_set_retrieve_function2(xcred,
tlshd_x509_retrieve_key_cb);

flags = GNUTLS_CLIENT;
ret = gnutls_init(&session, flags);
if (ret != GNUTLS_E_SUCCESS) {
tlshd_log_gnutls_error(ret);
goto out_free_creds;
goto out_free_certs;
}
gnutls_transport_set_int(session, parms->sockfd);
gnutls_session_set_ptr(session, parms);
Expand All @@ -315,17 +298,17 @@ static void tlshd_tls13_client_x509_handshake(struct tlshd_handshake_parms *parm
parms->peername, strlen(parms->peername));
if (ret != GNUTLS_E_SUCCESS) {
tlshd_log_gnutls_error(ret);
goto out_free_creds;
goto out_free_certs;
}
ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
if (ret != GNUTLS_E_SUCCESS) {
tlshd_log_gnutls_error(ret);
goto out_free_creds;
goto out_free_certs;
}
ret = tlshd_gnutls_priority_set(session, parms, 0);
if (ret != GNUTLS_E_SUCCESS) {
tlshd_log_gnutls_error(ret);
goto out_free_creds;
goto out_free_certs;
}
gnutls_certificate_set_verify_function(xcred,
tlshd_tls13_client_x509_verify_function);
Expand All @@ -334,6 +317,10 @@ static void tlshd_tls13_client_x509_handshake(struct tlshd_handshake_parms *parm

gnutls_deinit(session);

out_free_certs:
tlshd_x509_client_put_privkey();
tlshd_x509_client_put_certs();

out_free_creds:
gnutls_certificate_free_credentials(xcred);
}
Expand Down Expand Up @@ -417,11 +404,9 @@ static void tlshd_tls13_client_psk_handshake_one(struct tlshd_handshake_parms *p

tlshd_log_debug("start ClientHello handshake");
tlshd_start_tls_handshake(session, parms);
if (!parms->session_status) {
if (!parms->session_status)
/* PSK uses the same identity for both client and server */
parms->num_remote_peerids = 1;
parms->remote_peerid[0] = peerid;
}
g_array_append_val(parms->remote_peerids, peerid);

gnutls_deinit(session);

Expand All @@ -432,9 +417,10 @@ static void tlshd_tls13_client_psk_handshake_one(struct tlshd_handshake_parms *p

static void tlshd_tls13_client_psk_handshake(struct tlshd_handshake_parms *parms)
{
unsigned int i;
key_serial_t peerid;
guint i;

if (!parms->peerids) {
if (parms->peerids->len == 0) {
tlshd_log_error("No key identities");
return;
}
Expand All @@ -443,8 +429,9 @@ static void tlshd_tls13_client_psk_handshake(struct tlshd_handshake_parms *parms
* GnuTLS does not yet support multiple offered PskIdentities.
* Retry ClientHello with each identity on the kernel's list.
*/
for (i = 0; i < parms->num_peerids; i++) {
tlshd_tls13_client_psk_handshake_one(parms, parms->peerids[i]);
for (i = 0; i < parms->peerids->len; i++) {
peerid = g_array_index(parms->peerids, key_serial_t, i);
tlshd_tls13_client_psk_handshake_one(parms, peerid);
if (parms->session_status != EACCES)
break;
}
Expand Down Expand Up @@ -489,7 +476,6 @@ static int tlshd_quic_client_set_x509_session(struct tlshd_quic_conn *conn)
gnutls_certificate_credentials_t cred;
gnutls_session_t session;
int ret = -EINVAL;
char *cafile;

if (conn->cert_req != TLSHD_QUIC_NO_CERT_AUTH) {
if (!tlshd_x509_client_get_certs(parms) || !tlshd_x509_client_get_privkey(parms)) {
Expand All @@ -500,14 +486,9 @@ static int tlshd_quic_client_set_x509_session(struct tlshd_quic_conn *conn)
ret = gnutls_certificate_allocate_credentials(&cred);
if (ret)
goto err;
if (tlshd_config_get_client_truststore(&cafile)) {
ret = gnutls_certificate_set_x509_trust_file(cred, cafile, GNUTLS_X509_FMT_PEM);
free(cafile);
} else
ret = gnutls_certificate_set_x509_system_trust(cred);
if (ret < 0)
ret = tlshd_client_get_truststore(xcred);
if (ret != GNUTLS_E_SUCCESS)
goto err_cred;
tlshd_log_debug("System trust: Loaded %d certificate(s).", ret);

if (conn->cert_req == TLSHD_QUIC_NO_CERT_AUTH) {
gnutls_certificate_set_verify_flags(cred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2 |
Expand Down Expand Up @@ -546,6 +527,8 @@ static int tlshd_quic_client_set_x509_session(struct tlshd_quic_conn *conn)
err_cred:
gnutls_certificate_free_credentials(cred);
err:
tlshd_x509_client_put_privkey();
tlshd_x509_client_put_certs();
tlshd_log_gnutls_error(ret);
return ret;
}
Expand Down
Loading