diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml index 5d16bd9..3a0ee4f 100644 --- a/.github/workflows/makefile.yml +++ b/.github/workflows/makefile.yml @@ -6,6 +6,7 @@ jobs: build: runs-on: ubuntu-latest + permissions: read-all strategy: fail-fast: false matrix: diff --git a/ChangeLog b/ChangeLog index a46076e..a5640b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/NEWS b/NEWS index f6e6d92..60bd06e 100644 --- a/NEWS +++ b/NEWS @@ -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 diff --git a/README b/README index a26e010..a7b731a 100644 --- a/README +++ b/README @@ -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 diff --git a/README.md b/README.md index a26e010..a7b731a 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/configure.ac b/configure.ac index 818b30b..a6d9d09 100644 --- a/configure.ac +++ b/configure.ac @@ -18,7 +18,7 @@ dnl 02110-1301, USA. dnl AC_PREREQ([2.69]) -AC_INIT([ktls-utils],[1.1.0],[kernel-tls-handshake@lists.linux.dev]) +AC_INIT([ktls-utils],[1.2.0],[kernel-tls-handshake@lists.linux.dev]) AM_INIT_AUTOMAKE AM_SILENT_RULES([yes]) AC_CONFIG_SRCDIR([config.h.in]) diff --git a/src/tlshd/client.c b/src/tlshd/client.c index 9c8f512..0e648ed 100644 --- a/src/tlshd/client.c +++ b/src/tlshd/client.c @@ -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); @@ -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); @@ -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) @@ -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) @@ -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]; @@ -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, @@ -218,12 +244,6 @@ 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; @@ -231,34 +251,6 @@ 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, - &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; } @@ -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); @@ -283,22 +274,14 @@ 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); @@ -306,7 +289,7 @@ static void tlshd_tls13_client_x509_handshake(struct tlshd_handshake_parms *parm 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); @@ -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); @@ -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); } @@ -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); @@ -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; } @@ -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; } @@ -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)) { @@ -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 | @@ -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; } diff --git a/src/tlshd/config.c b/src/tlshd/config.c index be5d472..4c54d37 100644 --- a/src/tlshd/config.c +++ b/src/tlshd/config.c @@ -46,12 +46,6 @@ static GKeyFile *tlshd_configuration; -/** - * ALLPERMS exists in glibc, but not on musl, so we - * manually define TLSHD_ACCESSPERMS instead of using ALLPERMS. - */ -#define TLSHD_ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO) - /** * tlshd_config_init - Read tlshd's config file * @pathname: Pathname to config file @@ -99,15 +93,18 @@ bool tlshd_config_init(const gchar *pathname) for (i = 0; i < length; i++) { if (!strcmp(keyrings[i], ".nvme")) continue; + if (!strcmp(keyrings[i], ".nfs")) + continue; + if (!strcmp(keyrings[i], ".nfsd")) + continue; tlshd_keyring_link_session(keyrings[i]); } g_strfreev(keyrings); } - /* - * Always link the default nvme subsystem keyring into the - * session. - */ + /* The ".nvme", ".nfs", and ".nfsd" keyrings cannot be disabled. */ tlshd_keyring_link_session(".nvme"); + tlshd_keyring_link_session(".nfs"); + tlshd_keyring_link_session(".nfsd"); return true; } @@ -117,6 +114,12 @@ void tlshd_config_shutdown(void) g_key_file_free(tlshd_configuration); } +/** + * ALLPERMS exists in glibc, but not on musl, so we manually + * define TLSHD_ACCESSPERMS instead of using ALLPERMS. + */ +#define TLSHD_ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO) + /* * Expected file attributes */ @@ -140,7 +143,11 @@ static bool tlshd_config_read_datum(const char *pathname, gnutls_datum_t *data, fd = open(pathname, O_RDONLY); if (fd == -1) { - tlshd_log_perror("open"); + if (access(pathname, F_OK)) + tlshd_log_debug("tlshd cannot access \"%s\"", + pathname); + else + tlshd_log_perror("open"); goto out; } if (fstat(fd, &statbuf)) { @@ -189,16 +196,14 @@ static bool tlshd_config_read_datum(const char *pathname, gnutls_datum_t *data, */ bool tlshd_config_get_client_truststore(char **bundle) { - GError *error = NULL; gchar *pathname; pathname = g_key_file_get_string(tlshd_configuration, "authenticate.client", - "x509.truststore", &error); - if (!pathname) { - g_error_free(error); + "x509.truststore", NULL); + if (!pathname) return false; - } else if (access(pathname, F_OK)) { - tlshd_log_debug("client x509.truststore pathname \"%s\" is not accessible", pathname); + if (access(pathname, F_OK)) { + tlshd_log_debug("tlshd cannot access \"%s\"", pathname); g_free(pathname); return false; } @@ -212,6 +217,37 @@ bool tlshd_config_get_client_truststore(char **bundle) return true; } +/** + * tlshd_config_get_client_crl - Get CRL for ClientHello from .conf + * @result: OUT: pathname to CRL + * + * Return values: + * %false: pathname not retrieved + * %true: pathname retrieved successfully; caller must free @result using free(3) + */ +bool tlshd_config_get_client_crl(char **result) +{ + gchar *pathname; + + pathname = g_key_file_get_string(tlshd_configuration, "authenticate.client", + "x509.crl", NULL); + if (!pathname) + return false; + if (access(pathname, F_OK)) { + tlshd_log_debug("tlshd cannot access \"%s\"", pathname); + g_free(pathname); + return false; + } + + *result = strdup(pathname); + g_free(pathname); + if (!*result) + return false; + + tlshd_log_debug("Client x.509 crl is %s", *result); + return true; +} + /** * tlshd_config_get_client_certs - Get certs for ClientHello from .conf * @certs: OUT: in-memory certificates @@ -224,21 +260,14 @@ bool tlshd_config_get_client_truststore(char **bundle) bool tlshd_config_get_client_certs(gnutls_pcert_st *certs, unsigned int *certs_len) { - GError *error = NULL; gnutls_datum_t data; gchar *pathname; int ret; pathname = g_key_file_get_string(tlshd_configuration, "authenticate.client", - "x509.certificate", &error); - if (!pathname) { - g_error_free(error); - return false; - } else if (access(pathname, F_OK)) { - tlshd_log_debug("client x509.certificate pathname \"%s\" is not accessible", pathname); - g_free(pathname); + "x509.certificate", NULL); + if (!pathname) return false; - } if (!tlshd_config_read_datum(pathname, &data, TLSHD_OWNER, TLSHD_CERT_MODE)) { @@ -272,21 +301,14 @@ bool tlshd_config_get_client_certs(gnutls_pcert_st *certs, */ bool tlshd_config_get_client_privkey(gnutls_privkey_t *privkey) { - GError *error = NULL; gnutls_datum_t data; gchar *pathname; int ret; pathname = g_key_file_get_string(tlshd_configuration, "authenticate.client", - "x509.private_key", &error); - if (!pathname) { - g_error_free(error); - return false; - } else if (access(pathname, F_OK)) { - tlshd_log_debug("client x509.private_key pathname \"%s\" is not accessible", pathname); - g_free(pathname); + "x509.private_key", NULL); + if (!pathname) return false; - } if (!tlshd_config_read_datum(pathname, &data, TLSHD_OWNER, TLSHD_PRIVKEY_MODE)) { @@ -327,16 +349,14 @@ bool tlshd_config_get_client_privkey(gnutls_privkey_t *privkey) */ bool tlshd_config_get_server_truststore(char **bundle) { - GError *error = NULL; gchar *pathname; pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server", - "x509.truststore", &error); - if (!pathname) { - g_error_free(error); + "x509.truststore", NULL); + if (!pathname) return false; - } else if (access(pathname, F_OK)) { - tlshd_log_debug("server x509.truststore pathname \"%s\" is not accessible", pathname); + if (access(pathname, F_OK)) { + tlshd_log_debug("tlshd cannot access \"%s\"", pathname); g_free(pathname); return false; } @@ -350,6 +370,37 @@ bool tlshd_config_get_server_truststore(char **bundle) return true; } +/** + * tlshd_config_get_server_crl - Get CRL for ServerHello from .conf + * @result: OUT: pathname to CRL + * + * Return values: + * %false: pathname not retrieved + * %true: pathname retrieved successfully; caller must free @result using free(3) + */ +bool tlshd_config_get_server_crl(char **result) +{ + gchar *pathname; + + pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server", + "x509.crl", NULL); + if (!pathname) + return false; + if (access(pathname, F_OK)) { + tlshd_log_debug("tlshd cannot access \"%s\"", pathname); + g_free(pathname); + return false; + } + + *result = strdup(pathname); + g_free(pathname); + if (!*result) + return false; + + tlshd_log_debug("Server x.509 crl is %s", *result); + return true; +} + /** * tlshd_config_get_server_certs - Get certs for ServerHello from .conf * @certs: OUT: in-memory certificates @@ -362,21 +413,14 @@ bool tlshd_config_get_server_truststore(char **bundle) bool tlshd_config_get_server_certs(gnutls_pcert_st *certs, unsigned int *certs_len) { - GError *error = NULL; gnutls_datum_t data; gchar *pathname; int ret; pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server", - "x509.certificate", &error); - if (!pathname) { - g_error_free(error); - return false; - } else if (access(pathname, F_OK)) { - tlshd_log_debug("server x509.certificate pathname \"%s\" is not accessible", pathname); - g_free(pathname); + "x509.certificate", NULL); + if (!pathname) return false; - } if (!tlshd_config_read_datum(pathname, &data, TLSHD_OWNER, TLSHD_CERT_MODE)) { @@ -410,21 +454,14 @@ bool tlshd_config_get_server_certs(gnutls_pcert_st *certs, */ bool tlshd_config_get_server_privkey(gnutls_privkey_t *privkey) { - GError *error = NULL; gnutls_datum_t data; gchar *pathname; int ret; pathname = g_key_file_get_string(tlshd_configuration, "authenticate.server", - "x509.private_key", &error); - if (!pathname) { - g_error_free(error); - return false; - } else if (access(pathname, F_OK)) { - tlshd_log_debug("server x509.privkey pathname \"%s\" is not accessible", pathname); - g_free(pathname); + "x509.private_key", NULL); + if (!pathname) return false; - } if (!tlshd_config_read_datum(pathname, &data, TLSHD_OWNER, TLSHD_PRIVKEY_MODE)) { diff --git a/src/tlshd/handshake.c b/src/tlshd/handshake.c index b9de6b3..ed5c13b 100644 --- a/src/tlshd/handshake.c +++ b/src/tlshd/handshake.c @@ -93,6 +93,7 @@ void tlshd_start_tls_handshake(gnutls_session_t session, /* Any errors here should default to blocking access: */ parms->session_status = EACCES; switch (ret) { + case GNUTLS_E_CERTIFICATE_ERROR: case GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR: tlshd_log_cert_verification_error(session); break; @@ -181,16 +182,6 @@ void tlshd_service_socket(void) out: tlshd_genl_done(&parms); - - if (parms.keyring) - keyctl_unlink(parms.keyring, KEY_SPEC_SESSION_KEYRING); - - free(parms.peerids); - - if (parms.session_status) { - tlshd_log_failure(parms.peername, parms.peeraddr, - parms.peeraddr_len); - return; - } - tlshd_log_success(parms.peername, parms.peeraddr, parms.peeraddr_len); + tlshd_log_completion(&parms); + tlshd_genl_put_handshake_parms(&parms); } diff --git a/src/tlshd/keyring.c b/src/tlshd/keyring.c index f499a76..6aac02e 100644 --- a/src/tlshd/keyring.c +++ b/src/tlshd/keyring.c @@ -256,24 +256,21 @@ int tlshd_keyring_link_session(const char *keyring) key_serial_t serial; long ret; - if (!keyring) { + if (!keyring || keyring[0] == '\0') { tlshd_log_error("No keyring specified"); - errno = -EINVAL; return -1; } serial = find_key_by_type_and_desc("keyring", keyring, 0); - if (!serial) { - tlshd_log_debug("Failed to lookup keyring '%s'\n", - keyring); - errno = -ENOKEY; + if (serial == -1) { + tlshd_log_debug("Failed to find keyring '%s'\n", keyring); return -1; } ret = keyctl_link(serial, KEY_SPEC_SESSION_KEYRING); if (ret < 0) { - tlshd_log_debug("Failed to link keyring %s (%lx) error %d\n", - keyring, serial, errno); + tlshd_log_debug("Failed to link keyring '%s' (%lx): %s\n", + keyring, serial, strerror(errno)); return -1; } diff --git a/src/tlshd/ktls.c b/src/tlshd/ktls.c index 1615a40..40a26a4 100644 --- a/src/tlshd/ktls.c +++ b/src/tlshd/ktls.c @@ -350,32 +350,13 @@ static gnutls_priority_t tlshd_gnutls_priority_psk; static gnutls_priority_t tlshd_gnutls_priority_psk_sha256; static gnutls_priority_t tlshd_gnutls_priority_psk_sha384; -/** - * tlshd_gnutls_priority_init - Initialize GnuTLS priority caches - * - */ -int tlshd_gnutls_priority_init(void) +static int tlshd_gnutls_priority_init_list(const unsigned int *ciphers, + int cipher_count) { - const unsigned int *ciphers; - gnutls_priority_t pcache; - const char *errpos; char *pstring, *pstring_sha256, *pstring_sha384; + const char *errpos; int ret, i; - /* Retrieve the system default priority settings */ - ret = gnutls_priority_init(&pcache, NULL, &errpos); - if (ret != GNUTLS_E_SUCCESS) { - tlshd_log_gnutls_error(ret); - return -EIO; - } - - ret = gnutls_priority_cipher_list(pcache, &ciphers); - gnutls_priority_deinit(pcache); - if (ret < 0) { - tlshd_log_gnutls_error(ret); - return -EIO; - } - pstring = strdup("SECURE256:+SECURE128:-COMP-ALL"); if (!pstring) return -ENOMEM; @@ -407,7 +388,7 @@ int tlshd_gnutls_priority_init(void) return -ENOMEM; } - for (i = 0; i < ret; ++i) { + for (i = 0; i < cipher_count; ++i) { bool skip_sha256 = false; bool skip_sha384 = false; @@ -444,7 +425,6 @@ int tlshd_gnutls_priority_init(void) } tlshd_log_debug("x.509 priority string: %s\n", pstring); - ret = gnutls_priority_init(&tlshd_gnutls_priority_x509, pstring, &errpos); if (ret != GNUTLS_E_SUCCESS) { free(pstring_sha256); @@ -453,7 +433,6 @@ int tlshd_gnutls_priority_init(void) tlshd_log_gnutls_error(ret); return -EIO; } - pstring = tlshd_string_concat(pstring, ":+PSK:+DHE-PSK:+ECDHE-PSK"); if (!pstring) { free(pstring_sha256); @@ -463,7 +442,6 @@ int tlshd_gnutls_priority_init(void) } tlshd_log_debug("PSK priority string: %s\n", pstring); - ret = gnutls_priority_init(&tlshd_gnutls_priority_psk, pstring, &errpos); if (ret != GNUTLS_E_SUCCESS) { free(pstring_sha256); @@ -473,9 +451,7 @@ int tlshd_gnutls_priority_init(void) tlshd_log_gnutls_error(ret); return -EIO; } - free(pstring); - pstring = tlshd_string_concat(pstring_sha256, ":+DHE-PSK:+ECDHE-PSK"); if (!pstring) { free(pstring_sha384); @@ -485,7 +461,6 @@ int tlshd_gnutls_priority_init(void) } tlshd_log_debug("PSK SHA256 priority string: %s\n", pstring); - ret = gnutls_priority_init(&tlshd_gnutls_priority_psk_sha256, pstring, &errpos); if (ret != GNUTLS_E_SUCCESS) { @@ -496,9 +471,7 @@ int tlshd_gnutls_priority_init(void) tlshd_log_gnutls_error(ret); return -EIO; } - free(pstring); - pstring = tlshd_string_concat(pstring_sha384, ":+DHE-PSK:+ECDHE-PSK"); if (!pstring) { gnutls_priority_deinit(tlshd_gnutls_priority_psk_sha256); @@ -509,7 +482,6 @@ int tlshd_gnutls_priority_init(void) } tlshd_log_debug("PSK SHA384 priority string: %s\n", pstring); - ret = gnutls_priority_init(&tlshd_gnutls_priority_psk_sha384, pstring, &errpos); if (ret != GNUTLS_E_SUCCESS) { @@ -520,12 +492,45 @@ int tlshd_gnutls_priority_init(void) tlshd_log_gnutls_error(ret); return -EIO; } - free(pstring); return 0; } +/** + * tlshd_gnutls_priority_init - Initialize GnuTLS priority caches + * + * Returns zero on success, or a negative errno value if a failure + * occurred. + */ +int tlshd_gnutls_priority_init(void) +{ + const unsigned int *ciphers; + gnutls_priority_t pcache; + const char *errpos; + int ret; + + /* Retrieve the system default priority settings */ + ret = gnutls_priority_init(&pcache, NULL, &errpos); + if (ret != GNUTLS_E_SUCCESS) { + tlshd_log_gnutls_error(ret); + return -EIO; + } + + ret = gnutls_priority_cipher_list(pcache, &ciphers); + if (ret < 0) { + tlshd_log_gnutls_error(ret); + ret = -EIO; + goto out; + } + + ret = tlshd_gnutls_priority_init_list(ciphers, ret); + +out: + gnutls_priority_deinit(pcache); + return ret; +} + /** * tlshd_gnutls_priority_set - Initialize priorities per-session * @session: session to initialize diff --git a/src/tlshd/log.c b/src/tlshd/log.c index 3594d52..849027e 100644 --- a/src/tlshd/log.c +++ b/src/tlshd/log.c @@ -45,40 +45,27 @@ int tlshd_tls_debug; int tlshd_stderr; /** - * tlshd_log_success - Emit "handshake successful" notification - * @hostname: peer's DNS name - * @sap: peer's IP address - * @salen: length of IP address + * tlshd_log_completion - Emit completion notification + * @parms: handshake parameters * */ -void tlshd_log_success(const char *hostname, const struct sockaddr *sap, - socklen_t salen) +void tlshd_log_completion(struct tlshd_handshake_parms *parms) { - char buf[NI_MAXHOST]; + const char *status = "succeeded"; + int priority = LOG_INFO; - getnameinfo(sap, salen, buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); - syslog(LOG_INFO, "Handshake with %s (%s) was successful\n", - hostname, buf); -} + if (!tlshd_debug) + return; -/** - * tlshd_log_failure - Emit "handshake failed" notification - * @hostname: peer's DNS name - * @sap: peer's IP address - * @salen: length of IP address - * - */ -void tlshd_log_failure(const char *hostname, const struct sockaddr *sap, - socklen_t salen) -{ - if (salen) { - char buf[NI_MAXHOST]; - - getnameinfo(sap, salen, buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); - syslog(LOG_ERR, "Handshake with '%s' (%s) failed\n", - hostname, buf); - } else - syslog(LOG_ERR, "Handshake request failed\n"); + if (parms->session_status) { + status = "failed"; + priority = LOG_ERR; + } + if (parms->peername && parms->peeraddr) + syslog(priority, "Handshake with '%s' (%s) %s\n", + parms->peername, parms->peeraddr, status); + else + syslog(priority, "Handshake request %s\n", status); } /** diff --git a/src/tlshd/main.c b/src/tlshd/main.c index 649fe3f..f0f2aa7 100644 --- a/src/tlshd/main.c +++ b/src/tlshd/main.c @@ -61,6 +61,17 @@ static void usage(char *progname) fprintf(stderr, "usage: %s [-chsv]\n", progname); } +static void tlshd_sigint(int signum) +{ + if (signum == SIGINT) { + tlshd_gnutls_priority_deinit(); + tlshd_config_shutdown(); + tlshd_log_shutdown(); + tlshd_log_close(); + exit(EXIT_SUCCESS); + } +} + int main(int argc, char **argv) { static gchar config_file[PATH_MAX + 1] = "/etc/tlshd.conf"; @@ -113,6 +124,8 @@ int main(int argc, char **argv) return EXIT_FAILURE; } + signal(SIGINT, tlshd_sigint); + tlshd_genl_dispatch(); tlshd_gnutls_priority_deinit(); diff --git a/src/tlshd/netlink.c b/src/tlshd/netlink.c index ff9e35a..f716232 100644 --- a/src/tlshd/netlink.c +++ b/src/tlshd/netlink.c @@ -104,6 +104,8 @@ tlshd_accept_nl_policy[HANDSHAKE_A_ACCEPT_MAX + 1] = { [HANDSHAKE_A_ACCEPT_KEYRING] = { .type = NLA_U32, }, }; +static struct nl_sock *tlshd_notification_nls; + static int tlshd_genl_event_handler(struct nl_msg *msg, __attribute__ ((unused)) void *arg) { @@ -125,7 +127,13 @@ static int tlshd_genl_event_handler(struct nl_msg *msg, if (!fork()) { /* child */ + nlmsg_free(msg); + tlshd_genl_sock_close(tlshd_notification_nls); + tlshd_service_socket(); + + tlshd_gnutls_priority_deinit(); + tlshd_config_shutdown(); exit(EXIT_SUCCESS); } @@ -138,24 +146,23 @@ static int tlshd_genl_event_handler(struct nl_msg *msg, */ void tlshd_genl_dispatch(void) { - struct nl_sock *nls; int err, mcgrp; - err = tlshd_genl_sock_open(&nls); + err = tlshd_genl_sock_open(&tlshd_notification_nls); if (err) return; - nl_socket_modify_cb(nls, NL_CB_VALID, NL_CB_CUSTOM, + nl_socket_modify_cb(tlshd_notification_nls, NL_CB_VALID, NL_CB_CUSTOM, tlshd_genl_event_handler, NULL); /* Let the kernel know we are running */ - mcgrp = genl_ctrl_resolve_grp(nls, HANDSHAKE_FAMILY_NAME, + mcgrp = genl_ctrl_resolve_grp(tlshd_notification_nls, HANDSHAKE_FAMILY_NAME, HANDSHAKE_MCGRP_TLSHD); if (mcgrp < 0) { tlshd_log_error("Kernel handshake service is not available"); goto out_close; } - err = nl_socket_add_membership(nls, mcgrp); + err = nl_socket_add_membership(tlshd_notification_nls, mcgrp); if (err != NLE_SUCCESS) { tlshd_log_nl_error("nl_socket_add_membership", err); goto out_close; @@ -166,9 +173,9 @@ void tlshd_genl_dispatch(void) goto out_close; } - nl_socket_disable_seq_check(nls); + nl_socket_disable_seq_check(tlshd_notification_nls); while (true) { - err = nl_recvmsgs_default(nls); + err = nl_recvmsgs_default(tlshd_notification_nls); if (err < 0) { tlshd_log_nl_error("nl_recvmsgs", err); break; @@ -176,26 +183,21 @@ void tlshd_genl_dispatch(void) }; out_close: - tlshd_genl_sock_close(nls); + tlshd_genl_sock_close(tlshd_notification_nls); } static void tlshd_parse_peer_identity(struct tlshd_handshake_parms *parms, struct nlattr *head) { + key_serial_t peerid; + if (!head) { tlshd_log_debug("No peer identities found\n"); return; } - parms->num_peerids = 1; - - parms->peerids = calloc(parms->num_peerids, sizeof(key_serial_t)); - if (!parms->peerids) { - parms->num_peerids = 0; - return; - } - - parms->peerids[0] = nla_get_s32(head); + peerid = nla_get_s32(head); + g_array_append_val(parms->peerids, peerid); } #if LIBNL_VER_NUM >= LIBNL_VER(3,5) @@ -230,15 +232,14 @@ static void tlshd_parse_certificate(struct tlshd_handshake_parms *parms, parms->x509_privkey = nla_get_s32(tb[HANDSHAKE_A_X509_PRIVKEY]); } -static char tlshd_peername[NI_MAXHOST] = "unknown"; -static struct sockaddr_storage tlshd_peeraddr = { 0 }; - static int tlshd_genl_valid_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[HANDSHAKE_A_ACCEPT_MAX + 1]; struct tlshd_handshake_parms *parms = arg; + struct sockaddr_storage addr; + struct sockaddr *sap = NULL; + socklen_t salen, optlen; char *peername = NULL; - socklen_t optlen; int err; tlshd_log_debug("Parsing a valid netlink message\n"); @@ -251,18 +252,32 @@ static int tlshd_genl_valid_handler(struct nl_msg *msg, void *arg) } if (tb[HANDSHAKE_A_ACCEPT_SOCKFD]) { + char buf[NI_MAXHOST]; + int proto; + parms->sockfd = nla_get_s32(tb[HANDSHAKE_A_ACCEPT_SOCKFD]); - if (getpeername(parms->sockfd, parms->peeraddr, - &parms->peeraddr_len) == -1) { + + salen = sizeof(addr); + sap = (struct sockaddr *)&addr; + if (getpeername(parms->sockfd, sap, &salen) == -1) { tlshd_log_perror("getpeername"); return NL_STOP; } - optlen = sizeof(parms->ip_proto); + err = getnameinfo(sap, salen, buf, sizeof(buf), + NULL, 0, NI_NUMERICHOST); + if (err) { + tlshd_log_gai_error(err); + return NL_STOP; + } + parms->peeraddr = strdup(buf); + + optlen = sizeof(proto); if (getsockopt(parms->sockfd, SOL_SOCKET, SO_PROTOCOL, - &parms->ip_proto, &optlen) == -1) { + &proto, &optlen) == -1) { tlshd_log_perror("getsockopt (SO_PROTOCOL)"); return NL_STOP; } + parms->ip_proto = proto; } if (tb[HANDSHAKE_A_ACCEPT_MESSAGE_TYPE]) parms->handshake_type = nla_get_u32(tb[HANDSHAKE_A_ACCEPT_MESSAGE_TYPE]); @@ -287,24 +302,25 @@ static int tlshd_genl_valid_handler(struct nl_msg *msg, void *arg) tlshd_parse_certificate(parms, tb[HANDSHAKE_A_ACCEPT_CERTIFICATE]); if (peername) - strncpy(tlshd_peername, peername, sizeof(tlshd_peername) - 1); - else { - err = getnameinfo(parms->peeraddr, parms->peeraddr_len, - tlshd_peername, sizeof(tlshd_peername), + parms->peername = strdup(peername); + else if (sap) { + char buf[NI_MAXHOST]; + + err = getnameinfo(sap, salen, buf, sizeof(buf), NULL, 0, NI_NAMEREQD); if (err) { tlshd_log_gai_error(err); return NL_STOP; } + parms->peername = strdup(buf); } return NL_SKIP; } static const struct tlshd_handshake_parms tlshd_default_handshake_parms = { - .peername = tlshd_peername, - .peeraddr = (struct sockaddr *)&tlshd_peeraddr, - .peeraddr_len = sizeof(tlshd_peeraddr), + .peername = NULL, + .peeraddr = NULL, .sockfd = -1, .ip_proto = -1, .handshake_type = HANDSHAKE_MSG_TYPE_UNSPEC, @@ -313,11 +329,9 @@ static const struct tlshd_handshake_parms tlshd_default_handshake_parms = { .x509_cert = TLS_NO_CERT, .x509_privkey = TLS_NO_PRIVKEY, .peerids = NULL, - .num_peerids = 0, + .remote_peerids = NULL, .msg_status = 0, .session_status = EIO, - - .num_remote_peerids = 0, }; /** @@ -340,6 +354,9 @@ int tlshd_genl_get_handshake_parms(struct tlshd_handshake_parms *parms) *parms = tlshd_default_handshake_parms; + parms->peerids = g_array_new(FALSE, FALSE, sizeof(key_serial_t)); + parms->remote_peerids = g_array_new(FALSE, FALSE, sizeof(key_serial_t)); + ret = tlshd_genl_sock_open(&nls); if (ret) return ret; @@ -398,15 +415,31 @@ int tlshd_genl_get_handshake_parms(struct tlshd_handshake_parms *parms) return ret; } +/** + * tlshd_genl_put_handshake_parms - Release handshake resources + * @parms: handshake parameters to be released + * + */ +void tlshd_genl_put_handshake_parms(struct tlshd_handshake_parms *parms) +{ + if (parms->keyring) + keyctl_unlink(parms->keyring, KEY_SPEC_SESSION_KEYRING); + g_array_free(parms->peerids, TRUE); + g_array_free(parms->remote_peerids, TRUE); + free(parms->peername); + free(parms->peeraddr); +} + static int tlshd_genl_put_remote_peerids(struct nl_msg *msg, struct tlshd_handshake_parms *parms) { - unsigned int i; + key_serial_t peerid; + guint i; int err; - for (i = 0; i < parms->num_remote_peerids; i++) { - err = nla_put_s32(msg, HANDSHAKE_A_DONE_REMOTE_AUTH, - parms->remote_peerid[i]); + for (i = 0; i < parms->remote_peerids->len; i++) { + peerid = g_array_index(parms->remote_peerids, key_serial_t, i); + err = nla_put_s32(msg, HANDSHAKE_A_DONE_REMOTE_AUTH, peerid); if (err < 0) { tlshd_log_nl_error("nla_put peer id", err); return -1; @@ -416,7 +449,7 @@ static int tlshd_genl_put_remote_peerids(struct nl_msg *msg, } /** - * tlshd_genl_done - Indicate anon handshake has completed successfully + * tlshd_genl_done - Indicate handshake has completed successfully * @parms: buffer filled in with parameters * */ diff --git a/src/tlshd/server.c b/src/tlshd/server.c index 72ff6f5..db5db31 100644 --- a/src/tlshd/server.c +++ b/src/tlshd/server.c @@ -46,9 +46,6 @@ static gnutls_privkey_t tlshd_server_privkey; static unsigned int tlshd_server_certs_len = TLSHD_MAX_CERTS; static gnutls_pcert_st tlshd_server_certs[TLSHD_MAX_CERTS]; -/* - * XXX: After this point, tlshd_server_certs should be deinited on error. - */ static bool tlshd_x509_server_get_certs(struct tlshd_handshake_parms *parms) { if (parms->x509_cert != TLS_NO_CERT) @@ -59,9 +56,14 @@ static bool tlshd_x509_server_get_certs(struct tlshd_handshake_parms *parms) &tlshd_server_certs_len); } -/* - * XXX: After this point, tlshd_server_privkey should be deinited on error. - */ +static void tlshd_x509_server_put_certs(void) +{ + unsigned int i; + + for (i = 0; i < tlshd_server_certs_len; i++) + gnutls_pcert_deinit(&tlshd_server_certs[i]); +} + static bool tlshd_x509_server_get_privkey(struct tlshd_handshake_parms *parms) { if (parms->x509_privkey != TLS_NO_PRIVKEY) @@ -70,6 +72,11 @@ static bool tlshd_x509_server_get_privkey(struct tlshd_handshake_parms *parms) return tlshd_config_get_server_privkey(&tlshd_server_privkey); } +static void tlshd_x509_server_put_privkey(void) +{ + gnutls_privkey_deinit(tlshd_server_privkey); +} + static void tlshd_x509_log_issuers(const gnutls_datum_t *req_ca_rdn, int nreqs) { char issuer_dn[256]; @@ -126,6 +133,35 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session, return 0; } +static int tlshd_server_get_truststore(gnutls_certificate_credentials_t cred) +{ + char *pathname; + int ret; + + if (tlshd_config_get_server_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) + return ret; + tlshd_log_debug("System trust: Loaded %d certificate(s).", ret); + + if (tlshd_config_get_server_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; +} + /** * tlshd_server_x509_verify_function - Verify remote's x.509 certificate * @session: session in the midst of a handshake @@ -142,12 +178,9 @@ tlshd_x509_retrieve_key_cb(gnutls_session_t session, * verification failed. The server sends an ALERT to the client. */ static int tlshd_server_x509_verify_function(gnutls_session_t session, - struct tlshd_handshake_parms *parms) + __attribute__ ((unused)) 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, NULL, &status); @@ -161,10 +194,6 @@ static int tlshd_server_x509_verify_function(gnutls_session_t session, tlshd_log_gnutls_error(ret); goto 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) goto certificate_error; @@ -172,34 +201,6 @@ 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, - &parms->num_remote_peerids); - if (!peercerts || parms->num_remote_peerids == 0) { - tlshd_log_debug("The peer cert list is empty."); - goto certificate_error; - } - - tlshd_log_debug("The peer offered %u certificate(s).", - 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; certificate_error: @@ -218,7 +219,6 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm { gnutls_certificate_credentials_t xcred; gnutls_session_t session; - char *cafile; int ret; ret = gnutls_certificate_allocate_credentials(&xcred); @@ -226,32 +226,21 @@ static void tlshd_tls13_server_x509_handshake(struct tlshd_handshake_parms *parm tlshd_log_gnutls_error(ret); return; } - - if (tlshd_config_get_server_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_server_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_server_get_certs(parms)) { - goto out_free_creds; - } - if (!tlshd_x509_server_get_privkey(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 = gnutls_init(&session, GNUTLS_SERVER); 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); @@ -259,7 +248,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_creds; + goto out_free_certs; } gnutls_certificate_set_verify_function(xcred, tlshd_tls13_server_x509_verify_function); @@ -268,13 +257,39 @@ 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_creds; + goto out_free_certs; } tlshd_start_tls_handshake(session, parms); + if (tlshd_debug && + gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) { + const gnutls_datum_t *peercerts; + unsigned int i, num_certs = 0; + + peercerts = gnutls_certificate_get_peers(session, &num_certs); + for (i = 0; i < num_certs; i++) { + gnutls_x509_crt_t cert; + gnutls_datum_t cinfo; + + gnutls_x509_crt_init(&cert); + gnutls_x509_crt_import(cert, &peercerts[i], + GNUTLS_X509_FMT_DER); + if (gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_ONELINE, + &cinfo) == 0) { + tlshd_log_debug("Peer certificate: %s", cinfo.data); + gnutls_free(cinfo.data); + } + gnutls_x509_crt_deinit(cert); + } + } + gnutls_deinit(session); +out_free_certs: + tlshd_x509_server_put_privkey(); + tlshd_x509_server_put_certs(); + out_free_creds: gnutls_certificate_free_credentials(xcred); } @@ -316,8 +331,7 @@ static int tlshd_server_psk_cb(gnutls_session_t session, } /* PSK uses the same identity for both client and server */ - parms->remote_peerid[0] = psk; - parms->num_remote_peerids = 1; + g_array_append_val(parms->remote_peerids, psk); return 0; } @@ -453,8 +467,7 @@ static int tlshd_quic_server_psk_cb(gnutls_session_t session, const char *userna } /* PSK uses the same identity for both client and server */ - parms->remote_peerid[0] = psk; - parms->num_remote_peerids = 1; + g_array_append_val(parms->remote_peerids, psk); return 0; } @@ -475,15 +488,9 @@ static int tlshd_quic_server_set_x509_session(struct tlshd_quic_conn *conn) ret = gnutls_certificate_allocate_credentials(&cred); if (ret) goto err; - if (tlshd_config_get_server_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) - goto err_cred; - tlshd_log_debug("System trust: Loaded %d certificate(s).", ret); + ret = tlshd_server_get_truststore(cred); + if (ret) + goto err; gnutls_certificate_set_retrieve_function2(cred, tlshd_x509_retrieve_key_cb); @@ -528,6 +535,8 @@ static int tlshd_quic_server_set_x509_session(struct tlshd_quic_conn *conn) err_cred: gnutls_certificate_free_credentials(cred); err: + tlshd_x509_server_put_privkey(); + tlshd_x509_server_put_certs(); tlshd_log_gnutls_error(ret); return ret; } diff --git a/src/tlshd/tlshd.conf b/src/tlshd/tlshd.conf index 6ac13c8..620bd17 100644 --- a/src/tlshd/tlshd.conf +++ b/src/tlshd/tlshd.conf @@ -30,10 +30,12 @@ nl=0 [authenticate.client] #x509.truststore= +#x509.crl= #x509.certificate= #x509.private_key= [authenticate.server] #x509.truststore= +#x509.crl= #x509.certificate= #x509.private_key= diff --git a/src/tlshd/tlshd.conf.man b/src/tlshd/tlshd.conf.man index 9d6d92f..914261e 100644 --- a/src/tlshd/tlshd.conf.man +++ b/src/tlshd/tlshd.conf.man @@ -79,7 +79,13 @@ that contain handshake authentication tokens. .B tlshd links these keyrings into its session keyring. The configuration file may specify either a keyring's name or serial number. -The default is to provide no keyring. +.B tlshd +always includes the +.IR .nvme , +.IR .nfs , +and +.I .nfsd +keyrings on its session keyring. .P And, in this section, there are two subsections: .I [client] @@ -94,7 +100,7 @@ and it consults the settings in the .I [server] subsection when handling the server end of a handshake. .P -In each of these two subsections, there are three available options: +In each of these two subsections, there are four available options: .TP .B x509.truststore This option specifies the pathname of a file containing a @@ -104,6 +110,13 @@ If this option is not specified, .B tlshd uses the system's trust store. .TP +.B x509.crl +This option specifies the pathname of a file containing +PEM-encoded certificate revocation lists (CRL) that are to be +used to verify the revocation status of certificates during +each handshake. +If this option is not specified, CRL checking is skipped. +.TP .B x509.certificate This option specifies the pathname of a file containing a PEM-encoded x.509 certificate that is to be presented during diff --git a/src/tlshd/tlshd.h b/src/tlshd/tlshd.h index 135e1e0..a0dd47e 100644 --- a/src/tlshd/tlshd.h +++ b/src/tlshd/tlshd.h @@ -29,8 +29,7 @@ struct nl_sock; struct tlshd_handshake_parms { char *peername; - struct sockaddr *peeraddr; - socklen_t peeraddr_len; + char *peeraddr; int sockfd; int ip_proto; uint32_t handshake_type; @@ -39,14 +38,11 @@ struct tlshd_handshake_parms { key_serial_t keyring; key_serial_t x509_cert; key_serial_t x509_privkey; - key_serial_t *peerids; - unsigned int num_peerids; + GArray *peerids; + GArray *remote_peerids; int msg_status; unsigned int session_status; - - unsigned int num_remote_peerids; - key_serial_t remote_peerid[10]; }; /* client.c */ @@ -57,10 +53,12 @@ extern void tlshd_quic_clienthello_handshake(struct tlshd_handshake_parms *parms bool tlshd_config_init(const gchar *pathname); void tlshd_config_shutdown(void); bool tlshd_config_get_client_truststore(char **bundle); +bool tlshd_config_get_client_crl(char **result); bool tlshd_config_get_client_certs(gnutls_pcert_st *certs, unsigned int *certs_len); bool tlshd_config_get_client_privkey(gnutls_privkey_t *privkey); bool tlshd_config_get_server_truststore(char **bundle); +bool tlshd_config_get_server_crl(char **result); bool tlshd_config_get_server_certs(gnutls_pcert_st *certs, unsigned int *certs_len); bool tlshd_config_get_server_privkey(gnutls_privkey_t *privkey); @@ -96,11 +94,7 @@ extern void tlshd_log_init(const char *progname); extern void tlshd_log_shutdown(void); extern void tlshd_log_close(void); -extern void tlshd_log_success(const char *hostname, - const struct sockaddr *sap, socklen_t salen); -extern void tlshd_log_failure(const char *hostname, - const struct sockaddr *sap, socklen_t salen); - +extern void tlshd_log_completion(struct tlshd_handshake_parms *parms); extern void tlshd_log_debug(const char *fmt, ...); extern void tlshd_log_notice(const char *fmt, ...); extern void tlshd_log_error(const char *fmt, ...); @@ -118,6 +112,7 @@ void tlshd_log_nl_error(const char *msg, int err); /* netlink.c */ extern void tlshd_genl_dispatch(void); extern int tlshd_genl_get_handshake_parms(struct tlshd_handshake_parms *parms); +extern void tlshd_genl_put_handshake_parms(struct tlshd_handshake_parms *parms); extern void tlshd_genl_done(struct tlshd_handshake_parms *parms); /* server.c */