]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dnstls-openssl.c
tree-wide: "unparseable" → "unparsable"
[thirdparty/systemd.git] / src / resolve / resolved-dnstls-openssl.c
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
7 #include <openssl/bio.h>
8 #include <openssl/err.h>
9 #include <openssl/x509v3.h>
10
11 #include "io-util.h"
12 #include "resolved-dns-stream.h"
13 #include "resolved-dnstls.h"
14 #include "resolved-manager.h"
15
16 DEFINE_TRIVIAL_CLEANUP_FUNC(SSL*, SSL_free);
17 DEFINE_TRIVIAL_CLEANUP_FUNC(BIO*, BIO_free);
18
19 static int dnstls_flush_write_buffer(DnsStream *stream) {
20 ssize_t ss;
21
22 assert(stream);
23 assert(stream->encrypted);
24
25 if (stream->dnstls_data.buffer_offset < stream->dnstls_data.write_buffer->length) {
26 assert(stream->dnstls_data.write_buffer->data);
27
28 struct iovec iov[1];
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);
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 {
38 stream->dnstls_data.buffer_offset += ss;
39
40 if (stream->dnstls_data.buffer_offset < stream->dnstls_data.write_buffer->length) {
41 stream->dnstls_events |= EPOLLOUT;
42 return -EAGAIN;
43 } else {
44 BIO_reset(SSL_get_wbio(stream->dnstls_data.ssl));
45 stream->dnstls_data.buffer_offset = 0;
46 }
47 }
48 }
49
50 return 0;
51 }
52
53 int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
54 _cleanup_(BIO_freep) BIO *rb = NULL, *wb = NULL;
55 _cleanup_(SSL_freep) SSL *s = NULL;
56 int error, r;
57
58 assert(stream);
59 assert(stream->manager);
60 assert(server);
61
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)
68 return -ENOMEM;
69
70 BIO_get_mem_ptr(wb, &stream->dnstls_data.write_buffer);
71 stream->dnstls_data.buffer_offset = 0;
72
73 s = SSL_new(stream->manager->dnstls_data.ctx);
74 if (!s)
75 return -ENOMEM;
76
77 SSL_set_connect_state(s);
78 r = SSL_set_session(s, server->dnstls_data.session);
79 if (r == 0)
80 return -EIO;
81 SSL_set_bio(s, TAKE_PTR(rb), TAKE_PTR(wb));
82
83 if (server->manager->dns_over_tls_mode == DNS_OVER_TLS_YES) {
84 X509_VERIFY_PARAM *v;
85
86 SSL_set_verify(s, SSL_VERIFY_PEER, NULL);
87 v = SSL_get0_param(s);
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 }
98 }
99
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
111 ERR_clear_error();
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];
117
118 ERR_error_string_n(error, errbuf, sizeof(errbuf));
119 return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED),
120 "Failed to invoke SSL_do_handshake: %s", errbuf);
121 }
122 }
123
124 stream->encrypted = true;
125 stream->dnstls_data.ssl = TAKE_PTR(s);
126
127 r = dnstls_flush_write_buffer(stream);
128 if (r < 0 && r != -EAGAIN) {
129 SSL_free(TAKE_PTR(stream->dnstls_data.ssl));
130 return r;
131 }
132
133 return 0;
134 }
135
136 void 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
144 int dnstls_stream_on_io(DnsStream *stream, uint32_t revents) {
145 int error, r;
146
147 assert(stream);
148 assert(stream->encrypted);
149 assert(stream->dnstls_data.ssl);
150
151 /* Flush write buffer when requested by OpenSSL */
152 if ((revents & EPOLLOUT) && (stream->dnstls_events & EPOLLOUT)) {
153 r = dnstls_flush_write_buffer(stream);
154 if (r < 0)
155 return r;
156 }
157
158 if (stream->dnstls_data.shutdown) {
159 ERR_clear_error();
160 r = SSL_shutdown(stream->dnstls_data.ssl);
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) {
170 error = SSL_get_error(stream->dnstls_data.ssl, r);
171 if (IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) {
172 stream->dnstls_events = error == SSL_ERROR_WANT_READ ? EPOLLIN : EPOLLOUT;
173
174 r = dnstls_flush_write_buffer(stream);
175 if (r < 0)
176 return r;
177
178 return -EAGAIN;
179 } else if (error == SSL_ERROR_SYSCALL) {
180 if (errno > 0)
181 log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m");
182 } else {
183 char errbuf[256];
184
185 ERR_error_string_n(error, errbuf, sizeof(errbuf));
186 log_debug("Failed to invoke SSL_shutdown, ignoring: %s", errbuf);
187 }
188 }
189
190 stream->dnstls_events = 0;
191 stream->dnstls_data.shutdown = false;
192
193 r = dnstls_flush_write_buffer(stream);
194 if (r < 0)
195 return r;
196
197 dns_stream_unref(stream);
198 return DNSTLS_STREAM_CLOSED;
199 } else if (stream->dnstls_data.handshake <= 0) {
200 ERR_clear_error();
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;
206 r = dnstls_flush_write_buffer(stream);
207 if (r < 0)
208 return r;
209
210 return -EAGAIN;
211 } else {
212 char errbuf[256];
213
214 ERR_error_string_n(error, errbuf, sizeof(errbuf));
215 return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED),
216 "Failed to invoke SSL_do_handshake: %s",
217 errbuf);
218 }
219 }
220
221 stream->dnstls_events = 0;
222 r = dnstls_flush_write_buffer(stream);
223 if (r < 0)
224 return r;
225 }
226
227 return 0;
228 }
229
230 int dnstls_stream_shutdown(DnsStream *stream, int error) {
231 int ssl_error, r;
232 SSL_SESSION *s;
233
234 assert(stream);
235 assert(stream->encrypted);
236 assert(stream->dnstls_data.ssl);
237
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
248 if (error == ETIMEDOUT) {
249 ERR_clear_error();
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 }
256
257 stream->dnstls_events = 0;
258
259 r = dnstls_flush_write_buffer(stream);
260 if (r < 0)
261 return r;
262
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;
268 r = dnstls_flush_write_buffer(stream);
269 if (r < 0 && r != -EAGAIN)
270 return r;
271
272 if (!stream->dnstls_data.shutdown) {
273 stream->dnstls_data.shutdown = true;
274 dns_stream_ref(stream);
275 }
276 return -EAGAIN;
277 } else if (ssl_error == SSL_ERROR_SYSCALL) {
278 if (errno > 0)
279 log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m");
280 } else {
281 char errbuf[256];
282
283 ERR_error_string_n(ssl_error, errbuf, sizeof(errbuf));
284 log_debug("Failed to invoke SSL_shutdown, ignoring: %s", errbuf);
285 }
286 }
287
288 stream->dnstls_events = 0;
289 r = dnstls_flush_write_buffer(stream);
290 if (r < 0)
291 return r;
292 }
293
294 return 0;
295 }
296
297 ssize_t dnstls_stream_write(DnsStream *stream, const char *buf, size_t count) {
298 int error, r;
299 ssize_t ss;
300
301 assert(stream);
302 assert(stream->encrypted);
303 assert(stream->dnstls_data.ssl);
304 assert(buf);
305
306 ERR_clear_error();
307 ss = r = SSL_write(stream->dnstls_data.ssl, buf, count);
308 if (r <= 0) {
309 error = SSL_get_error(stream->dnstls_data.ssl, r);
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;
313 } else if (error == SSL_ERROR_ZERO_RETURN) {
314 stream->dnstls_events = 0;
315 ss = 0;
316 } else {
317 char errbuf[256];
318
319 ERR_error_string_n(error, errbuf, sizeof(errbuf));
320 log_debug("Failed to invoke SSL_write: %s", errbuf);
321 stream->dnstls_events = 0;
322 ss = -EPIPE;
323 }
324 } else
325 stream->dnstls_events = 0;
326
327 r = dnstls_flush_write_buffer(stream);
328 if (r < 0)
329 return r;
330
331 return ss;
332 }
333
334 ssize_t dnstls_stream_read(DnsStream *stream, void *buf, size_t count) {
335 int error, r;
336 ssize_t ss;
337
338 assert(stream);
339 assert(stream->encrypted);
340 assert(stream->dnstls_data.ssl);
341 assert(buf);
342
343 ERR_clear_error();
344 ss = r = SSL_read(stream->dnstls_data.ssl, buf, count);
345 if (r <= 0) {
346 error = SSL_get_error(stream->dnstls_data.ssl, r);
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;
350 } else if (error == SSL_ERROR_ZERO_RETURN) {
351 stream->dnstls_events = 0;
352 ss = 0;
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);
358 stream->dnstls_events = 0;
359 ss = -EPIPE;
360 }
361 } else
362 stream->dnstls_events = 0;
363
364 /* flush write buffer in cache of renegotiation */
365 r = dnstls_flush_write_buffer(stream);
366 if (r < 0)
367 return r;
368
369 return ss;
370 }
371
372 void dnstls_server_free(DnsServer *server) {
373 assert(server);
374
375 if (server->dnstls_data.session)
376 SSL_SESSION_free(server->dnstls_data.session);
377 }
378
379 int dnstls_manager_init(Manager *manager) {
380 int r;
381
382 assert(manager);
383
384 ERR_load_crypto_strings();
385 SSL_load_error_strings();
386
387 manager->dnstls_data.ctx = SSL_CTX_new(TLS_client_method());
388 if (!manager->dnstls_data.ctx)
389 return -ENOMEM;
390
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
397 r = SSL_CTX_set_default_verify_paths(manager->dnstls_data.ctx);
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));
402
403 return 0;
404 }
405
406 void dnstls_manager_free(Manager *manager) {
407 assert(manager);
408
409 if (manager->dnstls_data.ctx)
410 SSL_CTX_free(manager->dnstls_data.ctx);
411 }