]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dnstls-openssl.c
resolved: Fix build error due to missing include.
[thirdparty/systemd.git] / src / resolve / resolved-dnstls-openssl.c
CommitLineData
096cbdce
IT
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#if !ENABLE_DNS_OVER_TLS || !DNS_OVER_TLS_USE_OPENSSL
4#error This source file requires DNS-over-TLS to be enabled and OpenSSL to be available.
5#endif
6
096cbdce
IT
7#include <openssl/bio.h>
8#include <openssl/err.h>
eec394f1 9#include <openssl/x509v3.h>
096cbdce 10
29e719ce 11#include "io-util.h"
72938b93
YW
12#include "resolved-dns-stream.h"
13#include "resolved-dnstls.h"
d402edb7 14#include "resolved-manager.h"
72938b93 15
096cbdce
IT
16DEFINE_TRIVIAL_CLEANUP_FUNC(SSL*, SSL_free);
17DEFINE_TRIVIAL_CLEANUP_FUNC(BIO*, BIO_free);
18
04c4d919
IT
19static int dnstls_flush_write_buffer(DnsStream *stream) {
20 ssize_t ss;
21
22 assert(stream);
23 assert(stream->encrypted);
24
ab8cd6c9 25 if (stream->dnstls_data.buffer_offset < stream->dnstls_data.write_buffer->length) {
04c4d919
IT
26 assert(stream->dnstls_data.write_buffer->data);
27
28 struct iovec iov[1];
ab8cd6c9
IT
29 iov[0] = IOVEC_MAKE(stream->dnstls_data.write_buffer->data + stream->dnstls_data.buffer_offset,
30 stream->dnstls_data.write_buffer->length - stream->dnstls_data.buffer_offset);
04c4d919
IT
31 ss = dns_stream_writev(stream, iov, 1, DNS_STREAM_WRITE_TLS_DATA);
32 if (ss < 0) {
33 if (ss == -EAGAIN)
34 stream->dnstls_events |= EPOLLOUT;
35
36 return ss;
37 } else {
ab8cd6c9 38 stream->dnstls_data.buffer_offset += ss;
04c4d919 39
ab8cd6c9 40 if (stream->dnstls_data.buffer_offset < stream->dnstls_data.write_buffer->length) {
04c4d919
IT
41 stream->dnstls_events |= EPOLLOUT;
42 return -EAGAIN;
ab8cd6c9
IT
43 } else {
44 BIO_reset(SSL_get_wbio(stream->dnstls_data.ssl));
45 stream->dnstls_data.buffer_offset = 0;
04c4d919
IT
46 }
47 }
48 }
49
50 return 0;
51}
52
096cbdce 53int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
36f1946c 54 _cleanup_(BIO_freep) BIO *rb = NULL, *wb = NULL;
096cbdce 55 _cleanup_(SSL_freep) SSL *s = NULL;
36f1946c 56 int error, r;
096cbdce
IT
57
58 assert(stream);
e22c5b20 59 assert(stream->manager);
096cbdce
IT
60 assert(server);
61
04c4d919
IT
62 rb = BIO_new_socket(stream->fd, 0);
63 if (!rb)
64 return -ENOMEM;
65
66 wb = BIO_new(BIO_s_mem());
67 if (!wb)
096cbdce
IT
68 return -ENOMEM;
69
04c4d919 70 BIO_get_mem_ptr(wb, &stream->dnstls_data.write_buffer);
ab8cd6c9 71 stream->dnstls_data.buffer_offset = 0;
04c4d919 72
e22c5b20 73 s = SSL_new(stream->manager->dnstls_data.ctx);
096cbdce
IT
74 if (!s)
75 return -ENOMEM;
76
77 SSL_set_connect_state(s);
df70539f
YW
78 r = SSL_set_session(s, server->dnstls_data.session);
79 if (r == 0)
80 return -EIO;
04c4d919
IT
81 SSL_set_bio(s, TAKE_PTR(rb), TAKE_PTR(wb));
82
4310bfc2
IT
83 if (server->manager->dns_over_tls_mode == DNS_OVER_TLS_YES) {
84 X509_VERIFY_PARAM *v;
4310bfc2
IT
85
86 SSL_set_verify(s, SSL_VERIFY_PEER, NULL);
87 v = SSL_get0_param(s);
eec394f1
JT
88 if (server->server_name) {
89 X509_VERIFY_PARAM_set_hostflags(v, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
90 if (X509_VERIFY_PARAM_set1_host(v, server->server_name, 0) == 0)
91 return -ECONNREFUSED;
92 } else {
93 const unsigned char *ip;
94 ip = server->family == AF_INET ? (const unsigned char*) &server->address.in.s_addr : server->address.in6.s6_addr;
95 if (X509_VERIFY_PARAM_set1_ip(v, ip, FAMILY_ADDRESS_SIZE(server->family)) == 0)
96 return -ECONNREFUSED;
97 }
4310bfc2
IT
98 }
99
2e22a54f
GL
100 if (server->server_name) {
101 r = SSL_set_tlsext_host_name(s, server->server_name);
102 if (r <= 0) {
103 char errbuf[256];
104
105 error = ERR_get_error();
106 ERR_error_string_n(error, errbuf, sizeof(errbuf));
107 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set server name: %s", errbuf);
108 }
109 }
110
59c3fee2 111 ERR_clear_error();
04c4d919
IT
112 stream->dnstls_data.handshake = SSL_do_handshake(s);
113 if (stream->dnstls_data.handshake <= 0) {
114 error = SSL_get_error(s, stream->dnstls_data.handshake);
115 if (!IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
116 char errbuf[256];
096cbdce 117
04c4d919 118 ERR_error_string_n(error, errbuf, sizeof(errbuf));
df70539f
YW
119 return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED),
120 "Failed to invoke SSL_do_handshake: %s", errbuf);
04c4d919
IT
121 }
122 }
096cbdce
IT
123
124 stream->encrypted = true;
ab8cd6c9 125 stream->dnstls_data.ssl = TAKE_PTR(s);
04c4d919
IT
126
127 r = dnstls_flush_write_buffer(stream);
ab8cd6c9
IT
128 if (r < 0 && r != -EAGAIN) {
129 SSL_free(TAKE_PTR(stream->dnstls_data.ssl));
04c4d919 130 return r;
ab8cd6c9 131 }
096cbdce
IT
132
133 return 0;
134}
135
136void dnstls_stream_free(DnsStream *stream) {
137 assert(stream);
138 assert(stream->encrypted);
139
140 if (stream->dnstls_data.ssl)
141 SSL_free(stream->dnstls_data.ssl);
142}
143
04c4d919 144int dnstls_stream_on_io(DnsStream *stream, uint32_t revents) {
36f1946c 145 int error, r;
096cbdce
IT
146
147 assert(stream);
148 assert(stream->encrypted);
149 assert(stream->dnstls_data.ssl);
150
36f1946c 151 /* Flush write buffer when requested by OpenSSL */
04c4d919
IT
152 if ((revents & EPOLLOUT) && (stream->dnstls_events & EPOLLOUT)) {
153 r = dnstls_flush_write_buffer(stream);
154 if (r < 0)
155 return r;
156 }
157
096cbdce 158 if (stream->dnstls_data.shutdown) {
59c3fee2 159 ERR_clear_error();
096cbdce 160 r = SSL_shutdown(stream->dnstls_data.ssl);
8eadd291
YW
161 if (r == 0) {
162 stream->dnstls_events = 0;
163
164 r = dnstls_flush_write_buffer(stream);
165 if (r < 0)
166 return r;
167
168 return -EAGAIN;
169 } else if (r < 0) {
096cbdce 170 error = SSL_get_error(stream->dnstls_data.ssl, r);
8eadd291
YW
171 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
172 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
04c4d919
IT
173
174 r = dnstls_flush_write_buffer(stream);
175 if (r < 0)
176 return r;
177
096cbdce 178 return -EAGAIN;
8eadd291
YW
179 } else if (error == SSL_ERROR_SYSCALL) {
180 if (errno > 0)
181 log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m");
096cbdce
IT
182 } else {
183 char errbuf[256];
184
185 ERR_error_string_n(error, errbuf, sizeof(errbuf));
8eadd291 186 log_debug("Failed to invoke SSL_shutdown, ignoring: %s", errbuf);
096cbdce
IT
187 }
188 }
189
8eadd291
YW
190 stream->dnstls_events = 0;
191 stream->dnstls_data.shutdown = false;
192
04c4d919
IT
193 r = dnstls_flush_write_buffer(stream);
194 if (r < 0)
195 return r;
196
096cbdce
IT
197 dns_stream_unref(stream);
198 return DNSTLS_STREAM_CLOSED;
199 } else if (stream->dnstls_data.handshake <= 0) {
59c3fee2 200 ERR_clear_error();
096cbdce
IT
201 stream->dnstls_data.handshake = SSL_do_handshake(stream->dnstls_data.ssl);
202 if (stream->dnstls_data.handshake <= 0) {
203 error = SSL_get_error(stream->dnstls_data.ssl, stream->dnstls_data.handshake);
204 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
205 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
04c4d919
IT
206 r = dnstls_flush_write_buffer(stream);
207 if (r < 0)
208 return r;
209
096cbdce
IT
210 return -EAGAIN;
211 } else {
212 char errbuf[256];
213
214 ERR_error_string_n(error, errbuf, sizeof(errbuf));
baaa35ad
ZJS
215 return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED),
216 "Failed to invoke SSL_do_handshake: %s",
217 errbuf);
096cbdce
IT
218 }
219 }
220
221 stream->dnstls_events = 0;
04c4d919
IT
222 r = dnstls_flush_write_buffer(stream);
223 if (r < 0)
224 return r;
096cbdce
IT
225 }
226
227 return 0;
228}
229
230int dnstls_stream_shutdown(DnsStream *stream, int error) {
36f1946c 231 int ssl_error, r;
096cbdce
IT
232 SSL_SESSION *s;
233
234 assert(stream);
235 assert(stream->encrypted);
236 assert(stream->dnstls_data.ssl);
237
04c4d919
IT
238 if (stream->server) {
239 s = SSL_get1_session(stream->dnstls_data.ssl);
240 if (s) {
241 if (stream->server->dnstls_data.session)
242 SSL_SESSION_free(stream->server->dnstls_data.session);
243
244 stream->server->dnstls_data.session = s;
245 }
246 }
247
096cbdce 248 if (error == ETIMEDOUT) {
59c3fee2 249 ERR_clear_error();
096cbdce
IT
250 r = SSL_shutdown(stream->dnstls_data.ssl);
251 if (r == 0) {
252 if (!stream->dnstls_data.shutdown) {
253 stream->dnstls_data.shutdown = true;
254 dns_stream_ref(stream);
255 }
04c4d919 256
8eadd291
YW
257 stream->dnstls_events = 0;
258
04c4d919
IT
259 r = dnstls_flush_write_buffer(stream);
260 if (r < 0)
261 return r;
262
096cbdce
IT
263 return -EAGAIN;
264 } else if (r < 0) {
265 ssl_error = SSL_get_error(stream->dnstls_data.ssl, r);
266 if (IN_SET(ssl_error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
267 stream->dnstls_events = ssl_error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
04c4d919
IT
268 r = dnstls_flush_write_buffer(stream);
269 if (r < 0 && r != -EAGAIN)
270 return r;
271
096cbdce
IT
272 if (!stream->dnstls_data.shutdown) {
273 stream->dnstls_data.shutdown = true;
274 dns_stream_ref(stream);
275 }
276 return -EAGAIN;
8eadd291
YW
277 } else if (ssl_error == SSL_ERROR_SYSCALL) {
278 if (errno > 0)
279 log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m");
096cbdce
IT
280 } else {
281 char errbuf[256];
282
283 ERR_error_string_n(ssl_error, errbuf, sizeof(errbuf));
8eadd291 284 log_debug("Failed to invoke SSL_shutdown, ignoring: %s", errbuf);
096cbdce
IT
285 }
286 }
04c4d919
IT
287
288 stream->dnstls_events = 0;
289 r = dnstls_flush_write_buffer(stream);
290 if (r < 0)
291 return r;
096cbdce
IT
292 }
293
294 return 0;
295}
296
297ssize_t dnstls_stream_write(DnsStream *stream, const char *buf, size_t count) {
36f1946c 298 int error, r;
096cbdce
IT
299 ssize_t ss;
300
301 assert(stream);
302 assert(stream->encrypted);
303 assert(stream->dnstls_data.ssl);
304 assert(buf);
305
59c3fee2 306 ERR_clear_error();
096cbdce
IT
307 ss = r = SSL_write(stream->dnstls_data.ssl, buf, count);
308 if (r <= 0) {
8e740110 309 error = SSL_get_error(stream->dnstls_data.ssl, r);
096cbdce
IT
310 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
311 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
312 ss = -EAGAIN;
8e740110
YW
313 } else if (error == SSL_ERROR_ZERO_RETURN) {
314 stream->dnstls_events = 0;
315 ss = 0;
096cbdce
IT
316 } else {
317 char errbuf[256];
318
319 ERR_error_string_n(error, errbuf, sizeof(errbuf));
36f1946c 320 log_debug("Failed to invoke SSL_write: %s", errbuf);
8e740110 321 stream->dnstls_events = 0;
096cbdce
IT
322 ss = -EPIPE;
323 }
8e740110
YW
324 } else
325 stream->dnstls_events = 0;
096cbdce 326
04c4d919
IT
327 r = dnstls_flush_write_buffer(stream);
328 if (r < 0)
329 return r;
330
096cbdce
IT
331 return ss;
332}
333
334ssize_t dnstls_stream_read(DnsStream *stream, void *buf, size_t count) {
36f1946c 335 int error, r;
096cbdce
IT
336 ssize_t ss;
337
338 assert(stream);
339 assert(stream->encrypted);
340 assert(stream->dnstls_data.ssl);
341 assert(buf);
342
59c3fee2 343 ERR_clear_error();
096cbdce
IT
344 ss = r = SSL_read(stream->dnstls_data.ssl, buf, count);
345 if (r <= 0) {
8e740110 346 error = SSL_get_error(stream->dnstls_data.ssl, r);
096cbdce
IT
347 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
348 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
349 ss = -EAGAIN;
8e740110
YW
350 } else if (error == SSL_ERROR_ZERO_RETURN) {
351 stream->dnstls_events = 0;
352 ss = 0;
096cbdce
IT
353 } else {
354 char errbuf[256];
355
356 ERR_error_string_n(error, errbuf, sizeof(errbuf));
357 log_debug("Failed to invoke SSL_read: %s", errbuf);
8e740110 358 stream->dnstls_events = 0;
096cbdce
IT
359 ss = -EPIPE;
360 }
8e740110
YW
361 } else
362 stream->dnstls_events = 0;
04c4d919
IT
363
364 /* flush write buffer in cache of renegotiation */
365 r = dnstls_flush_write_buffer(stream);
366 if (r < 0)
367 return r;
368
096cbdce
IT
369 return ss;
370}
371
e22c5b20 372void dnstls_server_free(DnsServer *server) {
096cbdce
IT
373 assert(server);
374
e22c5b20
IT
375 if (server->dnstls_data.session)
376 SSL_SESSION_free(server->dnstls_data.session);
096cbdce
IT
377}
378
71a681ae 379int dnstls_manager_init(Manager *manager) {
e22c5b20 380 int r;
df70539f 381
e22c5b20 382 assert(manager);
096cbdce 383
e22c5b20
IT
384 ERR_load_crypto_strings();
385 SSL_load_error_strings();
71a681ae 386
df70539f 387 manager->dnstls_data.ctx = SSL_CTX_new(TLS_client_method());
71a681ae
IT
388 if (!manager->dnstls_data.ctx)
389 return -ENOMEM;
390
df70539f
YW
391 r = SSL_CTX_set_min_proto_version(manager->dnstls_data.ctx, TLS1_2_VERSION);
392 if (r == 0)
393 return -EIO;
394
395 (void) SSL_CTX_set_options(manager->dnstls_data.ctx, SSL_OP_NO_COMPRESSION);
396
4310bfc2 397 r = SSL_CTX_set_default_verify_paths(manager->dnstls_data.ctx);
df70539f
YW
398 if (r == 0)
399 return log_warning_errno(SYNTHETIC_ERRNO(EIO),
400 "Failed to load system trust store: %s",
401 ERR_error_string(ERR_get_error(), NULL));
71a681ae
IT
402
403 return 0;
e22c5b20 404}
04c4d919 405
e22c5b20
IT
406void dnstls_manager_free(Manager *manager) {
407 assert(manager);
408
409 if (manager->dnstls_data.ctx)
410 SSL_CTX_free(manager->dnstls_data.ctx);
096cbdce 411}