Skip to content

Commit ca76343

Browse files
authored
Merge pull request #128 from cgzones/tls
(D)TLS fixes, especially certificate verification
2 parents aa2be45 + 2664158 commit ca76343

File tree

11 files changed

+194
-158
lines changed

11 files changed

+194
-158
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ systemd-netlogd reads configuration files named `/etc/systemd/netlogd.conf` and
7171
Specifies the minimum delay before subsequent attempts to contact a Log server are made. 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.
7272

7373
TLSCertificateAuthMode=
74-
Specifies whether to validate the certificate. Takes one of no, allow, deny, warn. Defaults to 'no' which disables certificate validation.
74+
Specifies whether to validate the certificate. Takes one of no, allow, deny, warn. Defaults to 'deny' which rejects certificates failed to validate.
7575

7676
KeepAlive=
7777
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.

conf/netlogd.conf.in

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
[Network]
22
#Address=239.0.0.1:6000
33
#Protocol=udp
4+
#TLSCertificateAuthMode=deny
45
#LogFormat=rfc5424
6+
#Directory=
7+
#Namespace=
58
#StructuredData=
69
#UseSysLogStructuredData=no
710
#UseSysLogMsgId=no
@@ -10,5 +13,5 @@
1013
#KeepAliveTimeSec=
1114
#KeepAliveIntervalSec=
1215
#KeepAliveProbes=
13-
#NoDelay=
16+
#NoDelay=no
1417
#SendBuffer=

src/meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ systemd_netlogd_sources = files('''
120120
netlog/netlog-protocol.h
121121
netlog/netlog-dtls.c
122122
netlog/netlog-dtls.h
123+
netlog/netlog-ssl.c
124+
netlog/netlog-ssl.h
123125
netlog/netlog-tls.c
124126
netlog/netlog-tls.h
125127
'''.split())

src/netlog/netlog-dtls.c

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/* SPDX-License-Identifier: LGPL-2.1-or-later */
22

3+
#include "netlog-dtls.h"
4+
35
#include <arpa/inet.h>
46
#include <netinet/in.h>
57
#include <openssl/bio.h>
@@ -11,21 +13,28 @@
1113
#include "fd-util.h"
1214
#include "io-util.h"
1315
#include "iovec-util.h"
14-
#include "netlog-dtls.h"
16+
17+
#include "netlog-ssl.h"
1518

1619
static int dtls_write(DTLSManager *m, const char *buf, size_t count) {
1720
int r;
1821

1922
assert(m);
2023
assert(m->ssl);
24+
assert(m->pretty_address);
2125
assert(buf);
2226
assert(count > 0);
2327
assert(count < INT_MAX);
2428

2529
ERR_clear_error();
2630
r = SSL_write(m->ssl, buf, count);
27-
if (r <= 0)
28-
return log_error_errno(r, "DTLS: Failed to invoke SSL_write: %s", TLS_ERROR_STRING(SSL_get_error(m->ssl, r)));
31+
if (r <= 0) {
32+
int error = SSL_get_error(m->ssl, r);
33+
if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE))
34+
return log_info_errno(SYNTHETIC_ERRNO(EAGAIN), "DTLS: Failed to invoke SSL_write to %s: %s", m->pretty_address, TLS_ERROR_STRING(error));
35+
else
36+
return log_error_errno(SYNTHETIC_ERRNO(EPIPE), "DTLS: Failed to invoke SSL_write to %s: %s", m->pretty_address, TLS_ERROR_STRING(error));
37+
}
2938

3039
return log_debug("DTLS: Successful SSL_write: %d bytes", r);
3140
}
@@ -56,14 +65,15 @@ int dtls_connect(DTLSManager *m, SocketAddress *address) {
5665
_cleanup_free_ char *pretty = NULL;
5766
const SSL_CIPHER *cipher;
5867
socklen_t salen;
59-
SSL_CTX *ctx;
6068
struct timeval timeout = {
6169
.tv_sec = 3,
6270
.tv_usec = 0,
6371
};
64-
int fd, r;
72+
_cleanup_close_ int fd = -1;
73+
int r;
6574

6675
assert(m);
76+
assert(m->ctx);
6777
assert(address);
6878

6979
switch (address->sockaddr.sa.sa_family) {
@@ -91,39 +101,36 @@ int dtls_connect(DTLSManager *m, SocketAddress *address) {
91101

92102
log_debug("DTLS: Connected to remote server: '%s'", pretty);
93103

94-
ctx = SSL_CTX_new(DTLS_method());
95-
if (!ctx)
96-
return log_error_errno(SYNTHETIC_ERRNO(ENOMEM),
97-
"DTLS: Failed to allocate memory for SSL CTX: %m");
98-
99-
ssl = SSL_new(ctx);
100-
if (!ssl)
101-
return log_error_errno(SYNTHETIC_ERRNO(ENOMEM),
102-
"DTLS: Failed to allocate memory for ssl: %s",
103-
ERR_error_string(ERR_get_error(), NULL));
104-
105104
/* Create BIO from socket array! */
106105
bio = BIO_new_dgram(fd, BIO_NOCLOSE);
107106
if (!bio)
108107
return log_error_errno(SYNTHETIC_ERRNO(ENOMEM),
109108
"DTLS: Failed to allocate memory for bio: %m");
110109

111110
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &address);
111+
/* Set and activate timeouts */
112+
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
113+
114+
ssl = SSL_new(m->ctx);
115+
if (!ssl)
116+
return log_error_errno(SYNTHETIC_ERRNO(ENOMEM),
117+
"DTLS: Failed to allocate memory for ssl: %s",
118+
ERR_error_string(ERR_get_error(), NULL));
119+
112120
SSL_set_bio(ssl, bio, bio);
113-
m->bio = TAKE_PTR(bio);
121+
bio = NULL;
114122

115123
/* Certification verification */
116-
if (m->auth_mode != OPEN_SSL_CERTIFICATE_AUTH_MODE_NONE && m->auth_mode != OPEN_SSL_CERTIFICATE_AUTH_MODE_INVALID) {
124+
if (m->auth_mode != OPEN_SSL_CERTIFICATE_AUTH_MODE_NONE) {
117125
log_debug("DTLS: enable certificate verification");
118126

119-
SSL_set_ex_data(ssl, 0, m);
120-
SSL_set_ex_data(ssl, 1, address);
127+
SSL_set_ex_data(ssl, EX_DATA_TLSMANAGER, m);
128+
SSL_set_ex_data(ssl, EX_DATA_PRETTYADDRESS, pretty);
121129
SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_certificate_validity);
122130
} else {
123131
log_debug("DTLS: disable certificate verification");
124-
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
132+
SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
125133
}
126-
SSL_CTX_set_default_verify_paths(ctx);
127134

128135
r = SSL_connect(ssl);
129136
if (r <= 0)
@@ -150,12 +157,9 @@ int dtls_connect(DTLSManager *m, SocketAddress *address) {
150157
log_debug("DTLS: No certificates.");
151158
}
152159

153-
/* Set and activate timeouts */
154-
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
155-
156160
m->ssl = TAKE_PTR(ssl);
157-
m->ctx = ctx;
158-
m->fd = fd;
161+
m->fd = TAKE_FD(fd);
162+
m->pretty_address = TAKE_PTR(pretty);
159163

160164
m->connected = true;
161165
return 0;
@@ -173,6 +177,7 @@ void dtls_disconnect(DTLSManager *m) {
173177
m->ssl = NULL;
174178
}
175179

180+
m->pretty_address = mfree(m->pretty_address);
176181
m->fd = safe_close(m->fd);
177182
m->connected = false;
178183
}
@@ -189,13 +194,24 @@ void dtls_manager_free(DTLSManager *m) {
189194

190195
int dtls_manager_init(OpenSSLCertificateAuthMode auth_mode, DTLSManager **ret) {
191196
_cleanup_(dtls_manager_freep) DTLSManager *m = NULL;
197+
_cleanup_(SSL_CTX_freep) SSL_CTX *ctx = NULL;
198+
199+
ctx = SSL_CTX_new(DTLS_method());
200+
if (!ctx)
201+
return log_error_errno(SYNTHETIC_ERRNO(ENOMEM),
202+
"DTLS: Failed to allocate memory for SSL CTX: %m");
203+
204+
SSL_CTX_set_default_verify_paths(ctx);
205+
SSL_CTX_set_verify_depth(ctx, VERIFICATION_DEPTH + 1);
192206

193207
m = new(DTLSManager, 1);
194208
if (!m)
195209
return log_oom();
196210

197211
*m = (DTLSManager) {
198212
.auth_mode = auth_mode,
213+
.ctx = TAKE_PTR(ctx),
214+
.fd = -1,
199215
};
200216

201217
*ret = TAKE_PTR(m);

src/netlog/netlog-dtls.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#pragma once
33

44
#include <openssl/ssl.h>
5-
#include <openssl/bio.h>
65
#include <stdbool.h>
76

87
#include "socket-util.h"
@@ -13,9 +12,9 @@ typedef struct DTLSManager DTLSManager;
1312

1413
struct DTLSManager {
1514
SSL_CTX *ctx;
16-
BIO *bio;
1715
SSL *ssl;
1816

17+
char *pretty_address;
1918
int fd;
2019
bool connected;
2120

src/netlog/netlog-manager.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ int manager_new(const char *state_file, const char *cursor, Manager **ret) {
634634
.state_file = strdup(state_file),
635635
.protocol = SYSLOG_TRANSMISSION_PROTOCOL_UDP,
636636
.log_format = SYSLOG_TRANSMISSION_LOG_FORMAT_RFC_5424,
637-
.auth_mode = OPEN_SSL_CERTIFICATE_AUTH_MODE_INVALID,
637+
.auth_mode = OPEN_SSL_CERTIFICATE_AUTH_MODE_DENY,
638638
.connection_retry_usec = DEFAULT_CONNECTION_RETRY_USEC,
639639
.ratelimit = (const RateLimit) {
640640
RATELIMIT_INTERVAL_USEC,

src/netlog/netlog-ssl.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2+
3+
#include "netlog-ssl.h"
4+
5+
#include "alloc-util.h"
6+
#include "openssl-util.h"
7+
#include "socket-util.h"
8+
9+
#include "netlog-dtls.h"
10+
#include "netlog-tls.h"
11+
12+
static_assert(offsetof(TLSManager, auth_mode) == offsetof(DTLSManager, auth_mode));
13+
14+
/* inspired by SSL_set_verify(3) */
15+
int ssl_verify_certificate_validity(int preverify_ok, X509_STORE_CTX *store) {
16+
const SSL* ssl = X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx());
17+
const char *pretty = (const char *) SSL_get_ex_data(ssl, EX_DATA_PRETTYADDRESS);
18+
const TLSManager *m = (const TLSManager *) SSL_get_ex_data(ssl, EX_DATA_TLSMANAGER);
19+
const X509 *error_cert = X509_STORE_CTX_get_current_cert(store);
20+
int depth = X509_STORE_CTX_get_error_depth(store);
21+
int error = X509_STORE_CTX_get_error(store);
22+
char subject_buf[256];
23+
char issuer_buf[256];
24+
int log_level;
25+
26+
assert(store);
27+
assert(pretty);
28+
assert(m);
29+
30+
X509_NAME_oneline(X509_get_subject_name(error_cert), subject_buf, sizeof(subject_buf));
31+
X509_NAME_oneline(X509_get_issuer_name(error_cert), issuer_buf, sizeof(issuer_buf));
32+
33+
log_debug("TLS: Verifying SSL certificates of server %s: certificate: subject='%s' issuer='%s' depth=%d preverify_ok=%d error=%d/%s ...",
34+
pretty, subject_buf, issuer_buf, depth, preverify_ok, error, X509_verify_cert_error_string(error));
35+
36+
if (depth > VERIFICATION_DEPTH) {
37+
/*
38+
* From man:SSL_set_verif(3):
39+
*
40+
* Catch a too long certificate chain. The depth limit set using
41+
* SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
42+
* that whenever the "depth>verify_depth" condition is met, we
43+
* have violated the limit and want to log this error condition.
44+
* We must do it here, because the CHAIN_TOO_LONG error would not
45+
* be found explicitly; only errors introduced by cutting off the
46+
* additional certificates would be logged.
47+
*/
48+
preverify_ok = 0;
49+
error = X509_V_ERR_CERT_CHAIN_TOO_LONG;
50+
X509_STORE_CTX_set_error(store, error);
51+
}
52+
53+
if (preverify_ok) {
54+
log_debug("TLS: Verified SSL certificate of server=%s (certificate: subject='%s' issuer='%s' depth=%d): %s",
55+
pretty, subject_buf, issuer_buf, depth, X509_verify_cert_error_string(error));
56+
return preverify_ok;
57+
}
58+
59+
switch (m->auth_mode) {
60+
case OPEN_SSL_CERTIFICATE_AUTH_MODE_DENY:
61+
log_level = LOG_ERR;
62+
break;
63+
case OPEN_SSL_CERTIFICATE_AUTH_MODE_WARN:
64+
log_level = LOG_WARNING;
65+
preverify_ok = 1;
66+
break;
67+
case OPEN_SSL_CERTIFICATE_AUTH_MODE_ALLOW:
68+
log_level = LOG_DEBUG;
69+
preverify_ok = 1;
70+
break;
71+
default:
72+
assert_not_reached("Invalid certificate authentication mode"); /* mode NO does not set this callback */
73+
}
74+
75+
log_full(log_level, "TLS: Failed to verify certificate of server=%s (certificate: subject='%s' issuer='%s' depth=%d)%s: %s",
76+
pretty, subject_buf, issuer_buf, depth,
77+
preverify_ok ? ", ignoring" : "",
78+
X509_verify_cert_error_string(error));
79+
80+
return preverify_ok;
81+
}

src/netlog/netlog-ssl.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2+
#pragma once
3+
4+
#include <openssl/ssl.h>
5+
6+
#include "macro.h"
7+
8+
#define VERIFICATION_DEPTH 20
9+
10+
#define EX_DATA_TLSMANAGER 0
11+
#define EX_DATA_PRETTYADDRESS 1
12+
13+
int ssl_verify_certificate_validity(int preverify_ok, X509_STORE_CTX *store);
14+
15+
DEFINE_TRIVIAL_CLEANUP_FUNC(SSL_CTX*, SSL_CTX_free);

0 commit comments

Comments
 (0)