Skip to content

Commit

Permalink
Merge pull request #82 from ssahani/dev
Browse files Browse the repository at this point in the history
TLS: Allow to validate certificate
  • Loading branch information
ssahani authored May 13, 2024
2 parents 2532b84 + 787d223 commit e1244dc
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 15 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ systemd-netlogd reads configuration files named `/etc/systemd/netlogd.conf` and
Takes a time span value. The default unit is seconds, but other units may be specified,
see systemd.time(5). Defaults to 30 seconds and must not be smaller than 1 second.

TLSCertificateAuthMode=
Specifies whether to validate the certificate. Takes one of no, allow, deny, warn. Defaults to 'no' which disables certificate validation.

Optional settings

StructuredData=
Expand Down
3 changes: 3 additions & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ This will create a user systemd-journal-netlog
Takes a time span value. The default unit is seconds, but other units may be specified,
see systemd.time(5). Defaults to 30 seconds and must not be smaller than 1 second.
| ``TLSCertificateAuthMode=``
Specifies whether to validate the certificate. Takes one of no, allow, deny, warn. Defaults to 'no' which disables certificate validation.
|
|
| Optional settings
Expand Down
29 changes: 29 additions & 0 deletions src/netlog/netlog-conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,35 @@ int config_parse_log_format(const char *unit,
return 0;
}

int config_parse_tls_certificate_auth_mode(const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Manager *m = userdata;
int r;

assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
assert(m);

r = certificate_auth_mode_from_string(rvalue);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, -r, "Failed to parse '%s=%s', ignoring.", lvalue, rvalue);
return 0;
}

m->auth_mode = r;
return 0;
}

int config_parse_namespace(const char *unit,
const char *filename,
unsigned line,
Expand Down
11 changes: 11 additions & 0 deletions src/netlog/netlog-conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ int config_parse_log_format(const char *unit,
void *data,
void *userdata);

int config_parse_tls_certificate_auth_mode(const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata);

int config_parse_namespace(const char *unit,
const char *filename,
unsigned line,
Expand Down
19 changes: 10 additions & 9 deletions src/netlog/netlog-gperf.gperf
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
Network.Address, config_parse_netlog_remote_address, 0, 0
Network.Protocol, config_parse_protocol, 0, offsetof(Manager, protocol)
Network.LogFormat, config_parse_log_format, 0, offsetof(Manager, log_format)
Network.Directory, config_parse_string, 0, offsetof(Manager, dir)
Network.Namespace, config_parse_namespace, 0, offsetof(Manager, namespace)
Network.StructuredData, config_parse_string, 0, offsetof(Manager, structured_data)
Network.UseSysLogStructuredData, config_parse_bool, 0, offsetof(Manager, syslog_structured_data)
Network.UseSysLogMsgId, config_parse_bool, 0, offsetof(Manager, syslog_msgid)
Network.ConnectionRetrySec, config_parse_sec, 0, offsetof(Manager, connection_retry_usec)
Network.Address, config_parse_netlog_remote_address, 0, 0
Network.Protocol, config_parse_protocol, 0, offsetof(Manager, protocol)
Network.LogFormat, config_parse_log_format, 0, offsetof(Manager, log_format)
Network.Directory, config_parse_string, 0, offsetof(Manager, dir)
Network.Namespace, config_parse_namespace, 0, offsetof(Manager, namespace)
Network.StructuredData, config_parse_string, 0, offsetof(Manager, structured_data)
Network.UseSysLogStructuredData, config_parse_bool, 0, offsetof(Manager, syslog_structured_data)
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)
1 change: 1 addition & 0 deletions src/netlog/netlog-manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ int manager_new(const char *state_file, const char *cursor, Manager **ret) {
.state_file = strdup(state_file),
.protocol = SYSLOG_TRANSMISSION_PROTOCOL_UDP,
.log_format = SYSLOG_TRANSMISSION_LOG_FORMAT_RFC_5424,
.auth_mode = OPEN_SSL_CERTIFICATE_AUTH_MODE_INVALID,
.connection_retry_usec = DEFAULT_CONNECTION_RETRY_USEC,
.ratelimit = (const RateLimit) {
RATELIMIT_INTERVAL_USEC,
Expand Down
2 changes: 1 addition & 1 deletion src/netlog/netlog-manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ struct Manager {

SysLogTransmissionProtocol protocol;
SysLogTransmissionLogFormat log_format;
OpenSSLCertificateAuthMode auth_mode;

bool syslog_structured_data;
bool syslog_msgid;
bool encrypt;

DTLSManager *dtls;
TLSManager *tls;
Expand Down
119 changes: 116 additions & 3 deletions src/netlog/netlog-tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,104 @@
#include "io-util.h"
#include "iovec-util.h"
#include "netlog-tls.h"
#include "string-table.h"

static const char *const certificate_auth_mode_table[OPEN_SSL_CERTIFICATE_AUTH_MODE_MAX] = {
[OPEN_SSL_CERTIFICATE_AUTH_MODE_NONE] = "no",
[OPEN_SSL_CERTIFICATE_AUTH_MODE_ALLOW] = "allow",
[OPEN_SSL_CERTIFICATE_AUTH_MODE_DENY] = "deny",
[OPEN_SSL_CERTIFICATE_AUTH_MODE_WARN] = "warn",
};

DEFINE_STRING_TABLE_LOOKUP(certificate_auth_mode, int);

int ssl_verify_certificate_validity(int s, X509_STORE_CTX *store) {
SSL* ssl = X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx());
_cleanup_(OPENSSL_freep) void *subject = NULL, *issuer = NULL;
TLSManager *m = (TLSManager *) SSL_get_ex_data(ssl, 0);
X509 *cert = X509_STORE_CTX_get_current_cert(store);
int depth = X509_STORE_CTX_get_error_depth(store);
int error = X509_STORE_CTX_get_error(store);
int verify_mode = SSL_get_verify_mode(ssl);
int r;

assert(store);

log_debug("Verifying SSL ceritificates ...");

if (cert) {
subject = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
issuer = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
}

if (verify_mode == SSL_VERIFY_NONE) {
log_debug("SSL Certificate validation DISABLED but Error at depth: %d, issuer = %s, subject = %s: %s",
depth, (char *) subject, (char *) issuer, X509_verify_cert_error_string(error));

return 1;
}

r = SSL_get_verify_result(ssl);
if (r != X509_V_OK) {
switch(r) {
case X509_V_ERR_CERT_HAS_EXPIRED: {
switch (m->auth_mode) {
case OPEN_SSL_CERTIFICATE_AUTH_MODE_DENY: {
log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to verify certificate: %s", X509_verify_cert_error_string(r));
return 0;
}
break;
case OPEN_SSL_CERTIFICATE_AUTH_MODE_WARN: {
log_warning_errno(EINVAL,
"Failed to verify certificate: %s", X509_verify_cert_error_string(r));

return 1;
}
break;
case OPEN_SSL_CERTIFICATE_AUTH_MODE_ALLOW: {
log_debug("Failed to verify certificate: %s", X509_verify_cert_error_string(r));
return 1;
}

break;
default:
break;
}}
break;
case X509_V_ERR_CERT_REVOKED: {
switch (m->auth_mode) {
case OPEN_SSL_CERTIFICATE_AUTH_MODE_DENY: {
log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to verify certificate: %s", X509_verify_cert_error_string(r));
return 0;
}
break;
case OPEN_SSL_CERTIFICATE_AUTH_MODE_WARN: {
log_warning_errno(EINVAL,
"Failed to verify certificate: %s", X509_verify_cert_error_string(r));

return 1;
}
break;
case OPEN_SSL_CERTIFICATE_AUTH_MODE_ALLOW: {
log_debug("Failed to verify certificate: %s", X509_verify_cert_error_string(r));
return 1;
}
break;
default:
break;
}}
break;
default:
log_debug("Succesffuly validated certificated: %s", X509_verify_cert_error_string(r));
}
}

log_debug("SSL ceritificates verified: %s", X509_verify_cert_error_string(r));

return 1;
}

static int tls_write(TLSManager *m, const char *buf, size_t count) {
int r;
Expand Down Expand Up @@ -103,7 +201,6 @@ int tls_connect(TLSManager *m, SocketAddress *address) {
return log_error_errno(SYNTHETIC_ERRNO(ENOMEM),
"Failed to allocate memory for SSL CTX: %m");

SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
SSL_CTX_set_default_verify_paths(ctx);

ssl = SSL_new(ctx);
Expand All @@ -117,6 +214,17 @@ int tls_connect(TLSManager *m, SocketAddress *address) {
"Failed to SSL_set_fd: %s",
ERR_error_string(ERR_get_error(), NULL));

/* Cerification verification */
if (m->auth_mode != OPEN_SSL_CERTIFICATE_AUTH_MODE_NONE && m->auth_mode != OPEN_SSL_CERTIFICATE_AUTH_MODE_INVALID) {
log_debug("TLS: enable certificate verification");

SSL_set_ex_data(ssl, 0, m);
SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_certificate_validity);
} else {
log_debug("TLS: disable certificate verification");
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
}

r = SSL_connect(ssl);
if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(ENOMEM),
Expand All @@ -140,6 +248,7 @@ int tls_connect(TLSManager *m, SocketAddress *address) {
log_debug("SSL: Issuer: %s", (char *) issuer);
} else
log_debug("SSL: No certificates.");

}

r = fd_nonblock(fd, true);
Expand Down Expand Up @@ -181,13 +290,17 @@ void tls_manager_free(TLSManager *m) {
free(m);
}

int tls_manager_init(TLSManager **ret) {
int tls_manager_init(OpenSSLCertificateAuthMode auth, TLSManager **ret ) {
_cleanup_(tls_manager_freep) TLSManager *m = NULL;

m = new0(TLSManager, 1);
m = new(TLSManager, 1);
if (!m)
return log_oom();

*m = (TLSManager) {
.auth_mode = auth,
};

*ret = TAKE_PTR(m);
return 0;
}
18 changes: 17 additions & 1 deletion src/netlog/netlog-tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
#include "socket-util.h"
#include "openssl-util.h"

typedef enum OpenSSLCertificateAuthMode {
OPEN_SSL_CERTIFICATE_AUTH_MODE_NONE = 1 << 0,
OPEN_SSL_CERTIFICATE_AUTH_MODE_ALLOW = 1 << 1,
OPEN_SSL_CERTIFICATE_AUTH_MODE_DENY = 1 << 2,
OPEN_SSL_CERTIFICATE_AUTH_MODE_WARN = 1 << 3,
OPEN_SSL_CERTIFICATE_AUTH_MODE_MAX = 1 << 4,
OPEN_SSL_CERTIFICATE_AUTH_MODE_INVALID = -1,
} OpenSSLCertificateAuthMode;

typedef struct TLSManager TLSManager;

struct TLSManager {
Expand All @@ -18,14 +27,21 @@ struct TLSManager {
int fd;

bool connected;
OpenSSLCertificateAuthMode auth_mode;
};

void tls_manager_free(TLSManager *m);
int tls_manager_init(TLSManager **ret);
int tls_manager_init(OpenSSLCertificateAuthMode auth, TLSManager **ret);

int tls_connect(TLSManager *m, SocketAddress *addr);
void tls_disconnect(TLSManager *m);

int tls_stream_writev(TLSManager *m, const struct iovec *iov, size_t iovcnt);

int ssl_verify_certificate_validity(int status, X509_STORE_CTX *store);

const char *certificate_auth_mode_to_string(int v) _const_;
int certificate_auth_mode_from_string(const char *s) _pure_;


DEFINE_TRIVIAL_CLEANUP_FUNC(TLSManager*, tls_manager_free);
2 changes: 1 addition & 1 deletion src/netlog/systemd-netlogd.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ int main(int argc, char **argv) {
r = dtls_manager_init(&m->dtls);
break;
case SYSLOG_TRANSMISSION_PROTOCOL_TLS:
r = tls_manager_init(&m->tls);
r = tls_manager_init( m->auth_mode, &m->tls);
break;
default:
break;
Expand Down

0 comments on commit e1244dc

Please sign in to comment.