/src/fluent-bit/src/tls/flb_tls.c
Line | Count | Source |
1 | | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* Fluent Bit |
4 | | * ========== |
5 | | * Copyright (C) 2019-2020 The Fluent Bit Authors |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include <fluent-bit/flb_info.h> |
21 | | #include <fluent-bit/flb_time.h> |
22 | | #include <fluent-bit/flb_socket.h> |
23 | | |
24 | | #include "openssl.c" |
25 | | |
26 | | /* Config map for Upstream networking setup */ |
27 | | struct flb_config_map tls_configmap[] = { |
28 | | { |
29 | | FLB_CONFIG_MAP_BOOL, "tls", "off", |
30 | | 0, FLB_FALSE, 0, |
31 | | "Enable or disable TLS/SSL support", |
32 | | }, |
33 | | { |
34 | | FLB_CONFIG_MAP_BOOL, "tls.verify", "on", |
35 | | 0, FLB_FALSE, 0, |
36 | | "Force certificate validation", |
37 | | }, |
38 | | { |
39 | | FLB_CONFIG_MAP_BOOL, "tls.verify_client_cert", "off", |
40 | | 0, FLB_FALSE, 0, |
41 | | "Enable or disable client certificate verification", |
42 | | }, |
43 | | { |
44 | | FLB_CONFIG_MAP_INT, "tls.debug", "1", |
45 | | 0, FLB_FALSE, 0, |
46 | | "Set TLS debug verbosity level. It accept the following " |
47 | | "values: 0 (No debug), 1 (Error), 2 (State change), 3 " |
48 | | "(Informational) and 4 Verbose" |
49 | | }, |
50 | | { |
51 | | FLB_CONFIG_MAP_STR, "tls.ca_file", NULL, |
52 | | 0, FLB_FALSE, 0, |
53 | | "Absolute path to CA certificate file" |
54 | | }, |
55 | | { |
56 | | FLB_CONFIG_MAP_STR, "tls.ca_path", NULL, |
57 | | 0, FLB_FALSE, 0, |
58 | | "Absolute path to scan for certificate files" |
59 | | }, |
60 | | { |
61 | | FLB_CONFIG_MAP_STR, "tls.crt_file", NULL, |
62 | | 0, FLB_FALSE, 0, |
63 | | "Absolute path to Certificate file" |
64 | | }, |
65 | | { |
66 | | FLB_CONFIG_MAP_STR, "tls.key_file", NULL, |
67 | | 0, FLB_FALSE, 0, |
68 | | "Absolute path to private Key file" |
69 | | }, |
70 | | { |
71 | | FLB_CONFIG_MAP_STR, "tls.key_passwd", NULL, |
72 | | 0, FLB_FALSE, 0, |
73 | | "Optional password for tls.key_file file" |
74 | | }, |
75 | | |
76 | | { |
77 | | FLB_CONFIG_MAP_STR, "tls.vhost", NULL, |
78 | | 0, FLB_FALSE, 0, |
79 | | "Hostname to be used for TLS SNI extension" |
80 | | }, |
81 | | |
82 | | { |
83 | | FLB_CONFIG_MAP_BOOL, "tls.verify_hostname", "off", |
84 | | 0, FLB_FALSE, 0, |
85 | | "Enable or disable to verify hostname" |
86 | | }, |
87 | | |
88 | | { |
89 | | FLB_CONFIG_MAP_STR, "tls.min_version", NULL, |
90 | | 0, FLB_FALSE, 0, |
91 | | "Specify the minimum version of TLS" |
92 | | }, |
93 | | |
94 | | { |
95 | | FLB_CONFIG_MAP_STR, "tls.max_version", NULL, |
96 | | 0, FLB_FALSE, 0, |
97 | | "Specify the maximum version of TLS" |
98 | | }, |
99 | | |
100 | | { |
101 | | FLB_CONFIG_MAP_STR, "tls.ciphers", NULL, |
102 | | 0, FLB_FALSE, 0, |
103 | | "Specify TLS ciphers up to TLSv1.2" |
104 | | }, |
105 | | |
106 | | /* EOF */ |
107 | | {0} |
108 | | }; |
109 | | |
110 | | struct mk_list *flb_tls_get_config_map(struct flb_config *config) |
111 | 612 | { |
112 | 612 | struct mk_list *config_map; |
113 | | |
114 | 612 | config_map = flb_config_map_create(config, tls_configmap); |
115 | 612 | return config_map; |
116 | 612 | } |
117 | | |
118 | | |
119 | | static inline void io_tls_backup_event(struct flb_connection *connection, |
120 | | struct mk_event *backup) |
121 | 0 | { |
122 | 0 | if (connection != NULL && backup != NULL) { |
123 | 0 | memcpy(backup, &connection->event, sizeof(struct mk_event)); |
124 | 0 | } |
125 | 0 | } |
126 | | |
127 | | static inline void io_tls_restore_event(struct flb_connection *connection, |
128 | | struct mk_event *backup) |
129 | 0 | { |
130 | 0 | int result; |
131 | |
|
132 | 0 | if (connection != NULL && backup != NULL) { |
133 | 0 | if (MK_EVENT_IS_REGISTERED((&connection->event))) { |
134 | 0 | result = mk_event_del(connection->evl, &connection->event); |
135 | |
|
136 | 0 | assert(result == 0); |
137 | 0 | } |
138 | |
|
139 | 0 | if (MK_EVENT_IS_REGISTERED(backup)) { |
140 | 0 | connection->event.priority = backup->priority; |
141 | 0 | connection->event.handler = backup->handler; |
142 | |
|
143 | 0 | result = mk_event_add(connection->evl, |
144 | 0 | connection->fd, |
145 | 0 | backup->type, |
146 | 0 | backup->mask, |
147 | 0 | &connection->event); |
148 | |
|
149 | 0 | assert(result == 0); |
150 | 0 | } |
151 | 0 | } |
152 | 0 | } |
153 | | |
154 | | |
155 | | static inline int io_tls_event_switch(struct flb_tls_session *session, |
156 | | int mask) |
157 | 0 | { |
158 | 0 | struct mk_event_loop *event_loop; |
159 | 0 | struct mk_event *event; |
160 | 0 | int ret; |
161 | |
|
162 | 0 | event = &session->connection->event; |
163 | 0 | event_loop = session->connection->evl; |
164 | |
|
165 | 0 | if ((event->mask & mask) == 0) { |
166 | 0 | ret = mk_event_add(event_loop, |
167 | 0 | event->fd, |
168 | 0 | FLB_ENGINE_EV_THREAD, |
169 | 0 | mask, event); |
170 | |
|
171 | 0 | event->priority = FLB_ENGINE_PRIORITY_CONNECT; |
172 | |
|
173 | 0 | if (ret == -1) { |
174 | 0 | flb_error("[io_tls] error changing mask to %i", mask); |
175 | |
|
176 | 0 | return -1; |
177 | 0 | } |
178 | 0 | } |
179 | | |
180 | 0 | return 0; |
181 | 0 | } |
182 | | |
183 | | int flb_tls_load_system_certificates(struct flb_tls *tls) |
184 | 0 | { |
185 | 0 | return load_system_certificates(tls->ctx); |
186 | 0 | } |
187 | | |
188 | | struct flb_tls *flb_tls_create(int mode, |
189 | | int verify, |
190 | | int debug, |
191 | | const char *vhost, |
192 | | const char *ca_path, |
193 | | const char *ca_file, |
194 | | const char *crt_file, |
195 | | const char *key_file, |
196 | | const char *key_passwd) |
197 | 0 | { |
198 | 0 | void *backend; |
199 | 0 | struct flb_tls *tls; |
200 | | |
201 | | /* Assuming the TLS role based on the connection direction is wrong |
202 | | * but it's something we'll accept for the moment. |
203 | | */ |
204 | |
|
205 | 0 | backend = tls_context_create(verify, debug, mode, |
206 | 0 | vhost, ca_path, ca_file, |
207 | 0 | crt_file, key_file, key_passwd); |
208 | 0 | if (!backend) { |
209 | 0 | flb_error("[tls] could not create TLS backend"); |
210 | 0 | return NULL; |
211 | 0 | } |
212 | | |
213 | 0 | tls = flb_calloc(1, sizeof(struct flb_tls)); |
214 | 0 | if (!tls) { |
215 | 0 | flb_errno(); |
216 | 0 | tls_context_destroy(backend); |
217 | 0 | return NULL; |
218 | 0 | } |
219 | | |
220 | 0 | tls->verify = verify; |
221 | 0 | tls->debug = debug; |
222 | 0 | tls->mode = mode; |
223 | 0 | tls->verify_hostname = FLB_FALSE; |
224 | | #if defined(FLB_SYSTEM_WINDOWS) |
225 | | tls->certstore_name = NULL; |
226 | | tls->use_enterprise_store = FLB_FALSE; |
227 | | #endif |
228 | |
|
229 | 0 | if (vhost != NULL) { |
230 | 0 | tls->vhost = flb_strdup(vhost); |
231 | 0 | } |
232 | 0 | tls->ctx = backend; |
233 | |
|
234 | 0 | tls->api = &tls_openssl; |
235 | |
|
236 | 0 | return tls; |
237 | 0 | } |
238 | | |
239 | | int flb_tls_set_minmax_proto(struct flb_tls *tls, |
240 | | const char *min_version, const char *max_version) |
241 | 0 | { |
242 | 0 | if (tls->ctx) { |
243 | 0 | return tls->api->set_minmax_proto(tls, min_version, max_version); |
244 | 0 | } |
245 | | |
246 | 0 | return 0; |
247 | 0 | } |
248 | | |
249 | | int flb_tls_set_ciphers(struct flb_tls *tls, const char *ciphers) |
250 | 0 | { |
251 | 0 | if (tls->ctx) { |
252 | 0 | return tls->api->set_ciphers(tls, ciphers); |
253 | 0 | } |
254 | | |
255 | 0 | return 0; |
256 | 0 | } |
257 | | |
258 | | int flb_tls_init() |
259 | 4 | { |
260 | 4 | return tls_init(); |
261 | 4 | } |
262 | | |
263 | | int flb_tls_destroy(struct flb_tls *tls) |
264 | 0 | { |
265 | 0 | if (tls->ctx) { |
266 | 0 | tls->api->context_destroy(tls->ctx); |
267 | 0 | } |
268 | |
|
269 | 0 | if (tls->vhost != NULL) { |
270 | 0 | flb_free(tls->vhost); |
271 | 0 | } |
272 | |
|
273 | | #if defined(FLB_SYSTEM_WINDOWS) |
274 | | if (tls->certstore_name) { |
275 | | flb_free(tls->certstore_name); |
276 | | } |
277 | | #endif |
278 | |
|
279 | 0 | flb_free(tls); |
280 | |
|
281 | 0 | return 0; |
282 | 0 | } |
283 | | |
284 | | int flb_tls_set_alpn(struct flb_tls *tls, const char *alpn) |
285 | 0 | { |
286 | 0 | if (tls->ctx) { |
287 | 0 | return tls->api->context_alpn_set(tls->ctx, alpn); |
288 | 0 | } |
289 | | |
290 | 0 | return 0; |
291 | 0 | } |
292 | | |
293 | | int flb_tls_set_verify_client(struct flb_tls *tls, int verify_client) |
294 | 0 | { |
295 | 0 | if (!tls) { |
296 | 0 | return -1; |
297 | 0 | } |
298 | | |
299 | 0 | tls->verify_client = verify_client; |
300 | |
|
301 | 0 | if (tls->ctx && tls->api->context_set_verify_client) { |
302 | 0 | return tls->api->context_set_verify_client(tls->ctx, verify_client); |
303 | 0 | } |
304 | | |
305 | 0 | return 0; |
306 | 0 | } |
307 | | |
308 | | int flb_tls_set_verify_hostname(struct flb_tls *tls, int verify_hostname) |
309 | 0 | { |
310 | 0 | if (!tls) { |
311 | 0 | return -1; |
312 | 0 | } |
313 | | |
314 | 0 | tls->verify_hostname = !!verify_hostname; |
315 | |
|
316 | 0 | return 0; |
317 | 0 | } |
318 | | |
319 | | #if defined(FLB_SYSTEM_WINDOWS) |
320 | | int flb_tls_set_certstore_name(struct flb_tls *tls, const char *certstore_name) |
321 | | { |
322 | | if (tls) { |
323 | | return tls->api->set_certstore_name(tls, certstore_name); |
324 | | } |
325 | | |
326 | | return 0; |
327 | | } |
328 | | |
329 | | int flb_tls_set_use_enterprise_store(struct flb_tls *tls, int use_enterprise) |
330 | | { |
331 | | if (tls) { |
332 | | return tls->api->set_use_enterprise_store(tls, use_enterprise); |
333 | | } |
334 | | |
335 | | return 0; |
336 | | } |
337 | | |
338 | | int flb_tls_set_client_thumbprints(struct flb_tls *tls, const char *thumbprints) { |
339 | | if (tls && tls->api->set_client_thumbprints) { |
340 | | return tls->api->set_client_thumbprints(tls, thumbprints); |
341 | | } |
342 | | return -1; |
343 | | } |
344 | | #endif |
345 | | |
346 | | int flb_tls_net_read(struct flb_tls_session *session, void *buf, size_t len) |
347 | 0 | { |
348 | 0 | time_t timeout_timestamp; |
349 | 0 | time_t current_timestamp; |
350 | 0 | struct flb_tls *tls; |
351 | 0 | int ret; |
352 | |
|
353 | 0 | tls = session->tls; |
354 | |
|
355 | 0 | if (session->connection->net->io_timeout > 0) { |
356 | 0 | timeout_timestamp = time(NULL) + session->connection->net->io_timeout; |
357 | 0 | } |
358 | 0 | else { |
359 | 0 | timeout_timestamp = 0; |
360 | 0 | } |
361 | |
|
362 | 0 | retry_read: |
363 | 0 | ret = tls->api->net_read(session, buf, len); |
364 | |
|
365 | 0 | current_timestamp = time(NULL); |
366 | |
|
367 | 0 | if (ret == FLB_TLS_WANT_READ) { |
368 | 0 | if (timeout_timestamp > 0 && |
369 | 0 | timeout_timestamp <= current_timestamp) { |
370 | 0 | return ret; |
371 | 0 | } |
372 | | |
373 | 0 | goto retry_read; |
374 | 0 | } |
375 | 0 | else if (ret == FLB_TLS_WANT_WRITE) { |
376 | 0 | goto retry_read; |
377 | 0 | } |
378 | 0 | else if (ret < 0) { |
379 | 0 | return -1; |
380 | 0 | } |
381 | 0 | else if (ret == 0) { |
382 | 0 | return -1; |
383 | 0 | } |
384 | | |
385 | 0 | return ret; |
386 | 0 | } |
387 | | |
388 | | int flb_tls_net_read_async(struct flb_coro *co, |
389 | | struct flb_tls_session *session, |
390 | | void *buf, size_t len) |
391 | 0 | { |
392 | 0 | int event_restore_needed; |
393 | 0 | struct mk_event event_backup; |
394 | 0 | struct flb_tls *tls; |
395 | 0 | int ret; |
396 | |
|
397 | 0 | tls = session->tls; |
398 | |
|
399 | 0 | event_restore_needed = FLB_FALSE; |
400 | |
|
401 | 0 | io_tls_backup_event(session->connection, &event_backup); |
402 | |
|
403 | 0 | retry_read: |
404 | 0 | ret = tls->api->net_read(session, buf, len); |
405 | |
|
406 | 0 | if (ret == FLB_TLS_WANT_READ) { |
407 | 0 | event_restore_needed = FLB_TRUE; |
408 | |
|
409 | 0 | session->connection->coroutine = co; |
410 | |
|
411 | 0 | io_tls_event_switch(session, MK_EVENT_READ); |
412 | 0 | flb_coro_yield(co, FLB_FALSE); |
413 | |
|
414 | 0 | goto retry_read; |
415 | 0 | } |
416 | 0 | else if (ret == FLB_TLS_WANT_WRITE) { |
417 | 0 | event_restore_needed = FLB_TRUE; |
418 | |
|
419 | 0 | session->connection->coroutine = co; |
420 | |
|
421 | 0 | io_tls_event_switch(session, MK_EVENT_WRITE); |
422 | 0 | flb_coro_yield(co, FLB_FALSE); |
423 | |
|
424 | 0 | goto retry_read; |
425 | 0 | } |
426 | 0 | else |
427 | 0 | { |
428 | | /* We want this field to hold NULL at all times unless we are explicitly |
429 | | * waiting to be resumed. |
430 | | */ |
431 | 0 | session->connection->coroutine = NULL; |
432 | |
|
433 | 0 | if (ret <= 0) { |
434 | 0 | ret = -1; |
435 | 0 | } |
436 | 0 | } |
437 | | |
438 | 0 | if (event_restore_needed) { |
439 | | /* If we enter here it means we registered this connection |
440 | | * in the event loop, in which case we need to unregister it |
441 | | * and restore the original registration if there was one. |
442 | | * |
443 | | * We do it conditionally because in those cases in which |
444 | | * send succeeds on the first try we don't touch the event |
445 | | * and it wouldn't make sense to unregister and register for |
446 | | * the same event. |
447 | | */ |
448 | |
|
449 | 0 | io_tls_restore_event(session->connection, &event_backup); |
450 | 0 | } |
451 | |
|
452 | 0 | return ret; |
453 | 0 | } |
454 | | |
455 | | int flb_tls_net_write(struct flb_tls_session *session, |
456 | | const void *data, size_t len, size_t *out_len) |
457 | 0 | { |
458 | 0 | size_t total; |
459 | 0 | int ret; |
460 | 0 | struct flb_tls *tls; |
461 | |
|
462 | 0 | total = 0; |
463 | 0 | tls = session->tls; |
464 | |
|
465 | 0 | retry_write: |
466 | 0 | ret = tls->api->net_write(session, |
467 | 0 | (unsigned char *) data + total, |
468 | 0 | len - total); |
469 | |
|
470 | 0 | if (ret == FLB_TLS_WANT_WRITE) { |
471 | 0 | goto retry_write; |
472 | 0 | } |
473 | 0 | else if (ret == FLB_TLS_WANT_READ) { |
474 | 0 | goto retry_write; |
475 | 0 | } |
476 | 0 | else if (ret < 0) { |
477 | 0 | *out_len = total; |
478 | |
|
479 | 0 | return -1; |
480 | 0 | } |
481 | | |
482 | | /* Update counter and check if we need to continue writing */ |
483 | 0 | total += ret; |
484 | |
|
485 | 0 | if (total < len) { |
486 | 0 | goto retry_write; |
487 | 0 | } |
488 | | |
489 | 0 | *out_len = total; |
490 | |
|
491 | 0 | return ret; |
492 | 0 | } |
493 | | |
494 | | int flb_tls_net_write_async(struct flb_coro *co, |
495 | | struct flb_tls_session *session, |
496 | | const void *data, size_t len, size_t *out_len) |
497 | 0 | { |
498 | 0 | int event_restore_needed; |
499 | 0 | struct mk_event event_backup; |
500 | 0 | size_t total; |
501 | 0 | int ret; |
502 | 0 | struct flb_tls *tls; |
503 | |
|
504 | 0 | total = 0; |
505 | 0 | tls = session->tls; |
506 | |
|
507 | 0 | event_restore_needed = FLB_FALSE; |
508 | |
|
509 | 0 | io_tls_backup_event(session->connection, &event_backup); |
510 | |
|
511 | 0 | retry_write: |
512 | 0 | session->connection->coroutine = co; |
513 | |
|
514 | 0 | ret = tls->api->net_write(session, |
515 | 0 | (unsigned char *) data + total, |
516 | 0 | len - total); |
517 | |
|
518 | 0 | if (ret == FLB_TLS_WANT_WRITE) { |
519 | 0 | event_restore_needed = FLB_TRUE; |
520 | |
|
521 | 0 | io_tls_event_switch(session, MK_EVENT_WRITE); |
522 | |
|
523 | 0 | flb_coro_yield(co, FLB_FALSE); |
524 | |
|
525 | 0 | goto retry_write; |
526 | 0 | } |
527 | 0 | else if (ret == FLB_TLS_WANT_READ) { |
528 | 0 | event_restore_needed = FLB_TRUE; |
529 | |
|
530 | 0 | io_tls_event_switch(session, MK_EVENT_READ); |
531 | |
|
532 | 0 | flb_coro_yield(co, FLB_FALSE); |
533 | |
|
534 | 0 | goto retry_write; |
535 | 0 | } |
536 | 0 | else if (ret < 0) { |
537 | | /* We want this field to hold NULL at all times unless we are explicitly |
538 | | * waiting to be resumed. |
539 | | */ |
540 | |
|
541 | 0 | session->connection->coroutine = NULL; |
542 | 0 | *out_len = total; |
543 | |
|
544 | 0 | io_tls_restore_event(session->connection, &event_backup); |
545 | |
|
546 | 0 | return -1; |
547 | 0 | } |
548 | | |
549 | | /* Update counter and check if we need to continue writing */ |
550 | 0 | total += ret; |
551 | |
|
552 | 0 | if (total < len) { |
553 | 0 | io_tls_event_switch(session, MK_EVENT_WRITE); |
554 | |
|
555 | 0 | flb_coro_yield(co, FLB_FALSE); |
556 | |
|
557 | 0 | goto retry_write; |
558 | 0 | } |
559 | | |
560 | | /* We want this field to hold NULL at all times unless we are explicitly |
561 | | * waiting to be resumed. |
562 | | */ |
563 | | |
564 | 0 | session->connection->coroutine = NULL; |
565 | |
|
566 | 0 | *out_len = total; |
567 | |
|
568 | 0 | if (event_restore_needed) { |
569 | | /* If we enter here it means we registered this connection |
570 | | * in the event loop, in which case we need to unregister it |
571 | | * and restore the original registration if there was one. |
572 | | * |
573 | | * We do it conditionally because in those cases in which |
574 | | * send succeeds on the first try we don't touch the event |
575 | | * and it wouldn't make sense to unregister and register for |
576 | | * the same event. |
577 | | */ |
578 | |
|
579 | 0 | io_tls_restore_event(session->connection, &event_backup); |
580 | 0 | } |
581 | |
|
582 | 0 | return total; |
583 | 0 | } |
584 | | |
585 | | int flb_tls_client_session_create(struct flb_tls *tls, |
586 | | struct flb_connection *u_conn, |
587 | | struct flb_coro *co) |
588 | 0 | { |
589 | 0 | return flb_tls_session_create(tls, u_conn, co); |
590 | 0 | } |
591 | | |
592 | | int flb_tls_server_session_create(struct flb_tls *tls, |
593 | | struct flb_connection *connection, |
594 | | struct flb_coro *co) |
595 | 0 | { |
596 | 0 | return flb_tls_session_create(tls, connection, co); |
597 | 0 | } |
598 | | |
599 | | /* Create a TLS session (server) */ |
600 | | int flb_tls_session_create(struct flb_tls *tls, |
601 | | struct flb_connection *connection, |
602 | | struct flb_coro *co) |
603 | 0 | { |
604 | 0 | int event_restore_needed; |
605 | 0 | struct mk_event event_backup; |
606 | 0 | struct flb_tls_session *session; |
607 | 0 | int result; |
608 | 0 | char *vhost; |
609 | 0 | int flag; |
610 | |
|
611 | 0 | session = flb_calloc(1, sizeof(struct flb_tls_session)); |
612 | |
|
613 | 0 | if (session == NULL) { |
614 | 0 | return -1; |
615 | 0 | } |
616 | | |
617 | 0 | vhost = NULL; |
618 | |
|
619 | 0 | if (connection->type == FLB_UPSTREAM_CONNECTION) { |
620 | 0 | if (connection->upstream->proxied_host != NULL) { |
621 | 0 | vhost = flb_rtrim(connection->upstream->proxied_host, '.'); |
622 | 0 | } |
623 | 0 | else { |
624 | 0 | if (tls->vhost == NULL) { |
625 | 0 | vhost = flb_rtrim(connection->upstream->tcp_host, '.'); |
626 | 0 | } |
627 | 0 | } |
628 | 0 | } |
629 | | |
630 | | /* Create TLS session */ |
631 | 0 | session->ptr = tls->api->session_create(tls, connection->fd); |
632 | |
|
633 | 0 | if (session->ptr == NULL) { |
634 | 0 | flb_error("[tls] could not create TLS session for %s", |
635 | 0 | flb_connection_get_remote_address(connection)); |
636 | |
|
637 | 0 | if (vhost != NULL) { |
638 | 0 | flb_free(vhost); |
639 | 0 | } |
640 | |
|
641 | 0 | flb_free(session); |
642 | |
|
643 | 0 | return -1; |
644 | 0 | } |
645 | | |
646 | 0 | session->tls = tls; |
647 | 0 | session->connection = connection; |
648 | |
|
649 | 0 | result = 0; |
650 | |
|
651 | 0 | event_restore_needed = FLB_FALSE; |
652 | |
|
653 | 0 | io_tls_backup_event(session->connection, &event_backup); |
654 | |
|
655 | 0 | retry_handshake: |
656 | 0 | result = tls->api->net_handshake(tls, vhost, session->ptr); |
657 | |
|
658 | 0 | if (result != 0) { |
659 | 0 | if (result != FLB_TLS_WANT_READ && result != FLB_TLS_WANT_WRITE) { |
660 | 0 | result = -1; |
661 | |
|
662 | 0 | goto cleanup; |
663 | 0 | } |
664 | | |
665 | 0 | flag = 0; |
666 | |
|
667 | 0 | if (result == FLB_TLS_WANT_WRITE) { |
668 | 0 | flag = MK_EVENT_WRITE; |
669 | 0 | } |
670 | 0 | else if (result == FLB_TLS_WANT_READ) { |
671 | 0 | flag = MK_EVENT_READ; |
672 | 0 | } |
673 | | |
674 | | /* |
675 | | * If there are no coroutine thread context (th == NULL) it means this |
676 | | * TLS handshake is happening from a blocking code. Just sleep a bit |
677 | | * and retry. |
678 | | * |
679 | | * In the other case for an async socket 'th' is NOT NULL so the code |
680 | | * is under a coroutine context and it can yield. |
681 | | */ |
682 | 0 | if (co == NULL || !flb_upstream_is_async(connection->upstream)) { |
683 | 0 | flb_trace("[io_tls] server handshake connection #%i in process to %s", |
684 | 0 | connection->fd, |
685 | 0 | flb_connection_get_remote_address(connection)); |
686 | | |
687 | | /* Connect timeout */ |
688 | 0 | if (connection->net->connect_timeout > 0 && |
689 | 0 | connection->ts_connect_timeout > 0 && |
690 | 0 | connection->ts_connect_timeout <= time(NULL)) { |
691 | 0 | flb_error("[io_tls] handshake connection #%i to %s timed out after " |
692 | 0 | "%i seconds", |
693 | 0 | connection->fd, |
694 | 0 | flb_connection_get_remote_address(connection), |
695 | 0 | connection->net->connect_timeout); |
696 | |
|
697 | 0 | result = -1; |
698 | |
|
699 | 0 | goto cleanup; |
700 | 0 | } |
701 | | |
702 | 0 | flb_time_msleep(500); |
703 | |
|
704 | 0 | goto retry_handshake; |
705 | 0 | } |
706 | | |
707 | 0 | event_restore_needed = FLB_TRUE; |
708 | | |
709 | | /* |
710 | | * FIXME: if we need multiple reads we are invoking the same |
711 | | * system call multiple times. |
712 | | */ |
713 | |
|
714 | 0 | result = mk_event_add(connection->evl, |
715 | 0 | connection->fd, |
716 | 0 | FLB_ENGINE_EV_THREAD, |
717 | 0 | flag, |
718 | 0 | &connection->event); |
719 | |
|
720 | 0 | connection->event.priority = FLB_ENGINE_PRIORITY_CONNECT; |
721 | |
|
722 | 0 | if (result == -1) { |
723 | 0 | goto cleanup; |
724 | 0 | } |
725 | | |
726 | 0 | connection->coroutine = co; |
727 | |
|
728 | 0 | flb_coro_yield(co, FLB_FALSE); |
729 | | |
730 | | /* We want this field to hold NULL at all times unless we are explicitly |
731 | | * waiting to be resumed. |
732 | | */ |
733 | |
|
734 | 0 | connection->coroutine = NULL; |
735 | | |
736 | | /* This check's purpose is to abort when a timeout is detected. |
737 | | */ |
738 | 0 | if (connection->net_error == -1) { |
739 | 0 | goto retry_handshake; |
740 | 0 | } |
741 | 0 | else { |
742 | 0 | result = -1; |
743 | 0 | } |
744 | 0 | } |
745 | | |
746 | 0 | cleanup: |
747 | 0 | if (event_restore_needed) { |
748 | | /* If we enter here it means we registered this connection |
749 | | * in the event loop, in which case we need to unregister it |
750 | | * and restore the original registration if there was one. |
751 | | * |
752 | | * We do it conditionally because in those cases in which |
753 | | * send succeeds on the first try we don't touch the event |
754 | | * and it wouldn't make sense to unregister and register for |
755 | | * the same event. |
756 | | */ |
757 | |
|
758 | 0 | io_tls_restore_event(session->connection, &event_backup); |
759 | 0 | } |
760 | |
|
761 | 0 | if (result != 0) { |
762 | 0 | flb_tls_session_destroy(session); |
763 | 0 | } |
764 | 0 | else { |
765 | 0 | connection->tls_session = session; |
766 | 0 | } |
767 | |
|
768 | 0 | if (vhost != NULL) { |
769 | 0 | flb_free(vhost); |
770 | 0 | } |
771 | |
|
772 | 0 | return result; |
773 | 0 | } |
774 | | |
775 | | const char *flb_tls_session_get_alpn(struct flb_tls_session *session) |
776 | 0 | { |
777 | 0 | if (session->ptr != NULL) { |
778 | 0 | return session->tls->api->session_alpn_get(session); |
779 | 0 | } |
780 | | |
781 | 0 | return NULL; |
782 | 0 | } |
783 | | |
784 | | int flb_tls_session_destroy(struct flb_tls_session *session) |
785 | 0 | { |
786 | 0 | int ret; |
787 | |
|
788 | 0 | session->connection->tls_session = NULL; |
789 | |
|
790 | 0 | if (session->ptr != NULL) { |
791 | 0 | ret = session->tls->api->session_destroy(session->ptr); |
792 | |
|
793 | 0 | if (ret == -1) { |
794 | 0 | return -1; |
795 | 0 | } |
796 | | |
797 | 0 | flb_free(session); |
798 | 0 | } |
799 | | |
800 | 0 | return 0; |
801 | 0 | } |
802 | | |
803 | | int flb_tls_session_invalidate(struct flb_tls_session *session) |
804 | 0 | { |
805 | 0 | if (session == NULL || session->tls == NULL) { |
806 | 0 | return -1; |
807 | 0 | } |
808 | | |
809 | 0 | if (session->ptr != NULL && session->tls->api->session_invalidate != NULL) { |
810 | 0 | session->tls->api->session_invalidate(session->ptr); |
811 | 0 | } |
812 | |
|
813 | 0 | return 0; |
814 | 0 | } |