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