From 27fcca7003d7de163a6da28a80ca562eb74cca8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Wed, 6 Nov 2024 14:57:42 +0100 Subject: [PATCH] Add option TLSServerCertificate= Support specifying a path to a custom certificate, e.g. for self-signed certificates. --- README.md | 3 +++ conf/netlogd.conf.in | 1 + src/netlog/netlog-conf.c | 5 +++++ src/netlog/netlog-dtls.c | 16 ++++++++++++++-- src/netlog/netlog-dtls.h | 2 +- src/netlog/netlog-gperf.gperf | 1 + src/netlog/netlog-manager.c | 1 + src/netlog/netlog-manager.h | 1 + src/netlog/netlog-tls.c | 16 ++++++++++++++-- src/netlog/netlog-tls.h | 2 +- src/netlog/systemd-netlogd.c | 4 ++-- 11 files changed, 44 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4f42cec..35fbc53 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,9 @@ systemd-netlogd reads configuration files named `/etc/systemd/netlogd.conf` and TLSCertificateAuthMode= Specifies whether to validate the certificate. Takes one of no, allow, deny, warn. Defaults to 'deny' which rejects certificates failed to validate. + TLSServerCertificate= + Specify a custom certificate to validate the server against. Takes a path to a certificate file in PEM format. + KeepAlive= Takes a boolean argument. If true, the TCP/IP stack will send a keep alive message after 2h (depending on the configuration of /proc/sys/net/ipv4/tcp_keepalive_time) for all TCP streams accepted on this socket. This controls the SO_KEEPALIVE socket option (see socket(7) and the TCP Keepalive HOWTO for details.) Defaults to false. diff --git a/conf/netlogd.conf.in b/conf/netlogd.conf.in index fa5b938..4ebcae8 100644 --- a/conf/netlogd.conf.in +++ b/conf/netlogd.conf.in @@ -2,6 +2,7 @@ #Address=239.0.0.1:6000 #Protocol=udp #TLSCertificateAuthMode=deny +#TLSServerCertificate= #LogFormat=rfc5424 #Directory= #Namespace= diff --git a/src/netlog/netlog-conf.c b/src/netlog/netlog-conf.c index 608b57d..48a5ee0 100644 --- a/src/netlog/netlog-conf.c +++ b/src/netlog/netlog-conf.c @@ -221,6 +221,11 @@ int manager_parse_config_file(Manager *m) { && m->protocol != SYSLOG_TRANSMISSION_PROTOCOL_DTLS) log_warning("TLSCertificateAuthMode= set but unencrypted %s connection specified.", protocol_to_string(m->protocol)); + if (m->server_cert + && m->protocol != SYSLOG_TRANSMISSION_PROTOCOL_TLS + && m->protocol != SYSLOG_TRANSMISSION_PROTOCOL_DTLS) + log_warning("TLSServerCertificate= set but unencrypted %s connection specified.", protocol_to_string(m->protocol)); + if (m->dir && m->namespace) log_warning("Ignoring Namespace= setting since Directory= is set."); diff --git a/src/netlog/netlog-dtls.c b/src/netlog/netlog-dtls.c index aa4bef2..ff89e58 100644 --- a/src/netlog/netlog-dtls.c +++ b/src/netlog/netlog-dtls.c @@ -192,16 +192,28 @@ void dtls_manager_free(DTLSManager *m) { free(m); } -int dtls_manager_init(OpenSSLCertificateAuthMode auth_mode, DTLSManager **ret) { +int dtls_manager_init(OpenSSLCertificateAuthMode auth_mode, const char *server_cert, DTLSManager **ret) { _cleanup_(dtls_manager_freep) DTLSManager *m = NULL; _cleanup_(SSL_CTX_freep) SSL_CTX *ctx = NULL; + int r; ctx = SSL_CTX_new(DTLS_method()); if (!ctx) return log_error_errno(SYNTHETIC_ERRNO(ENOMEM), "DTLS: Failed to allocate memory for SSL CTX: %m"); - SSL_CTX_set_default_verify_paths(ctx); + if (server_cert) { + r = SSL_CTX_load_verify_file(ctx, server_cert); + if (r != 1) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),"DTLS: Failed to load CA certificate from '%s': %s", + server_cert, ERR_error_string(ERR_get_error(), NULL)); + } else { + r = SSL_CTX_set_default_verify_paths(ctx); + if (r != 1) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "DTLS: Failed to load default CA certificates: %s", + ERR_error_string(ERR_get_error(), NULL)); + } + SSL_CTX_set_verify_depth(ctx, VERIFICATION_DEPTH + 1); m = new(DTLSManager, 1); diff --git a/src/netlog/netlog-dtls.h b/src/netlog/netlog-dtls.h index 39cf62a..fdf24c9 100644 --- a/src/netlog/netlog-dtls.h +++ b/src/netlog/netlog-dtls.h @@ -22,7 +22,7 @@ struct DTLSManager { }; void dtls_manager_free(DTLSManager *m); -int dtls_manager_init(OpenSSLCertificateAuthMode auth_mode, DTLSManager **ret); +int dtls_manager_init(OpenSSLCertificateAuthMode auth_mode, const char *server_cert, DTLSManager **ret); int dtls_connect(DTLSManager *m, SocketAddress *addr); void dtls_disconnect(DTLSManager *m); diff --git a/src/netlog/netlog-gperf.gperf b/src/netlog/netlog-gperf.gperf index 41da965..d7836aa 100644 --- a/src/netlog/netlog-gperf.gperf +++ b/src/netlog/netlog-gperf.gperf @@ -25,6 +25,7 @@ Network.UseSysLogStructuredData, config_parse_bool, 0, off Network.UseSysLogMsgId, config_parse_bool, 0, offsetof(Manager, syslog_msgid) Network.ConnectionRetrySec, config_parse_sec, 0, offsetof(Manager, connection_retry_usec) Network.TLSCertificateAuthMode, config_parse_tls_certificate_auth_mode, 0, offsetof(Manager, auth_mode) +Network.TLSServerCertificate, config_parse_string, 0, offsetof(Manager, server_cert) Network.KeepAlive, config_parse_bool, 0, offsetof(Manager, keep_alive) Network.KeepAliveTimeSec, config_parse_sec, 0, offsetof(Manager, keep_alive_time) Network.KeepAliveIntervalSec, config_parse_sec, 0, offsetof(Manager, keep_alive_interval) diff --git a/src/netlog/netlog-manager.c b/src/netlog/netlog-manager.c index 9835b24..8bf2d94 100644 --- a/src/netlog/netlog-manager.c +++ b/src/netlog/netlog-manager.c @@ -599,6 +599,7 @@ void manager_free(Manager *m) { free(m->dtls); free(m->tls); + free(m->server_cert); free(m->server_name); diff --git a/src/netlog/netlog-manager.h b/src/netlog/netlog-manager.h index 426856f..ba578c1 100644 --- a/src/netlog/netlog-manager.h +++ b/src/netlog/netlog-manager.h @@ -73,6 +73,7 @@ struct Manager { SysLogTransmissionProtocol protocol; SysLogTransmissionLogFormat log_format; OpenSSLCertificateAuthMode auth_mode; + char *server_cert; bool syslog_structured_data; bool syslog_msgid; diff --git a/src/netlog/netlog-tls.c b/src/netlog/netlog-tls.c index d1c8d4d..3abc6cb 100644 --- a/src/netlog/netlog-tls.c +++ b/src/netlog/netlog-tls.c @@ -192,16 +192,28 @@ void tls_manager_free(TLSManager *m) { free(m); } -int tls_manager_init(OpenSSLCertificateAuthMode auth, TLSManager **ret ) { +int tls_manager_init(OpenSSLCertificateAuthMode auth, const char *server_cert, TLSManager **ret ) { _cleanup_(tls_manager_freep) TLSManager *m = NULL; _cleanup_(SSL_CTX_freep) SSL_CTX *ctx = NULL; + int r; ctx = SSL_CTX_new(TLS_client_method()); if (!ctx) return log_error_errno(SYNTHETIC_ERRNO(ENOMEM), "TLS: Failed to allocate memory for SSL CTX: %m"); - SSL_CTX_set_default_verify_paths(ctx); + if (server_cert) { + r = SSL_CTX_load_verify_file(ctx, server_cert); + if (r != 1) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),"TLS: Failed to load CA certificate from '%s': %s", + server_cert, ERR_error_string(ERR_get_error(), NULL)); + } else { + r = SSL_CTX_set_default_verify_paths(ctx); + if (r != 1) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TLS: Failed to load default CA certificates: %s", + ERR_error_string(ERR_get_error(), NULL)); + } + SSL_CTX_set_verify_depth(ctx, VERIFICATION_DEPTH + 1); m = new(TLSManager, 1); diff --git a/src/netlog/netlog-tls.h b/src/netlog/netlog-tls.h index bb7f883..6f3fd69 100644 --- a/src/netlog/netlog-tls.h +++ b/src/netlog/netlog-tls.h @@ -29,7 +29,7 @@ struct TLSManager { }; void tls_manager_free(TLSManager *m); -int tls_manager_init(OpenSSLCertificateAuthMode auth, TLSManager **ret); +int tls_manager_init(OpenSSLCertificateAuthMode auth, const char *server_cert, TLSManager **ret); int tls_connect(TLSManager *m, SocketAddress *addr); void tls_disconnect(TLSManager *m); diff --git a/src/netlog/systemd-netlogd.c b/src/netlog/systemd-netlogd.c index 18c0231..0f59b10 100644 --- a/src/netlog/systemd-netlogd.c +++ b/src/netlog/systemd-netlogd.c @@ -183,10 +183,10 @@ int main(int argc, char **argv) { switch (m->protocol) { case SYSLOG_TRANSMISSION_PROTOCOL_DTLS: - r = dtls_manager_init(m->auth_mode, &m->dtls); + r = dtls_manager_init(m->auth_mode, m->server_cert, &m->dtls); break; case SYSLOG_TRANSMISSION_PROTOCOL_TLS: - r = tls_manager_init(m->auth_mode, &m->tls); + r = tls_manager_init(m->auth_mode, m->server_cert, &m->tls); break; default: break;