blob: 4ec81a303ad4e37e45da0c1b56cfe982df6097a4 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file openssl/tls_udp.c DTLS backend using OpenSSL
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6
7#include <sys/time.h>
8#include <openssl/ssl.h>
9#include <openssl/err.h>
10#include <re_types.h>
11#include <re_fmt.h>
12#include <re_mem.h>
13#include <re_mbuf.h>
14#include <re_list.h>
15#include <re_hash.h>
16#include <re_sa.h>
17#include <re_srtp.h>
18#include <re_udp.h>
19#include <re_tmr.h>
20#include <re_tls.h>
21#include "tls.h"
22
23
24#define DEBUG_MODULE "dtls"
25#define DEBUG_LEVEL 5
26#include <re_dbg.h>
27
28
29enum {
30 MTU_DEFAULT = 1400,
31 MTU_FALLBACK = 548,
32};
33
34
35struct dtls_sock {
36 struct sa peer;
37 struct udp_helper *uh;
38 struct udp_sock *us;
39 struct hash *ht;
40 struct mbuf *mb;
41 dtls_conn_h *connh;
42 void *arg;
43 size_t mtu;
44};
45
46
47/* NOTE: shadow struct defined in tls_*.c */
48struct tls_conn {
49 SSL *ssl; /* inheritance */
50#ifdef TLS_BIO_OPAQUE
51 BIO_METHOD *biomet;
52#endif
53 BIO *sbio_out;
54 BIO *sbio_in;
55 struct tmr tmr;
56 struct sa peer;
57 struct le he;
58 struct dtls_sock *sock;
59 dtls_estab_h *estabh;
60 dtls_recv_h *recvh;
61 dtls_close_h *closeh;
62 void *arg;
63 bool active;
64 bool up;
65};
66
67
68static int bio_create(BIO *b)
69{
70#ifdef TLS_BIO_OPAQUE
71 BIO_set_init(b, 1);
72 BIO_set_data(b, NULL);
73 BIO_set_flags(b, 0);
74#else
75 b->init = 1;
76 b->num = 0;
77 b->ptr = NULL;
78 b->flags = 0;
79#endif
80
81 return 1;
82}
83
84
85static int bio_destroy(BIO *b)
86{
87 if (!b)
88 return 0;
89
90#ifdef TLS_BIO_OPAQUE
91 BIO_set_init(b, 0);
92 BIO_set_data(b, NULL);
93 BIO_set_flags(b, 0);
94#else
95 b->ptr = NULL;
96 b->init = 0;
97 b->flags = 0;
98#endif
99
100 return 1;
101}
102
103
104static int bio_write(BIO *b, const char *buf, int len)
105{
106#ifdef TLS_BIO_OPAQUE
107 struct tls_conn *tc = BIO_get_data(b);
108#else
109 struct tls_conn *tc = b->ptr;
110#endif
111 struct mbuf *mb;
112 enum {SPACE = 4};
113 int err;
114
115 mb = mbuf_alloc(SPACE + len);
116 if (!mb)
117 return -1;
118
119 mb->pos = SPACE;
120 (void)mbuf_write_mem(mb, (void *)buf, len);
121 mb->pos = SPACE;
122
123 err = udp_send_helper(tc->sock->us, &tc->peer, mb, tc->sock->uh);
124
125 mem_deref(mb);
126
127 return err ? -1 : len;
128}
129
130
131static long bio_ctrl(BIO *b, int cmd, long num, void *ptr)
132{
133#ifdef TLS_BIO_OPAQUE
134 struct tls_conn *tc = BIO_get_data(b);
135#else
136 struct tls_conn *tc = b->ptr;
137#endif
138 (void)num;
139 (void)ptr;
140
141 switch (cmd) {
142
143 case BIO_CTRL_FLUSH:
144 /* The OpenSSL library needs this */
145 return 1;
146
147#if defined (BIO_CTRL_DGRAM_QUERY_MTU)
148 case BIO_CTRL_DGRAM_QUERY_MTU:
149 return tc ? tc->sock->mtu : MTU_DEFAULT;
150#endif
151
152#if defined (BIO_CTRL_DGRAM_GET_FALLBACK_MTU)
153 case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
154 return MTU_FALLBACK;
155#endif
156 }
157
158 return 0;
159}
160
161
162#ifdef TLS_BIO_OPAQUE
163
164static BIO_METHOD *bio_method_udp(void)
165{
166 BIO_METHOD *method;
167
168 method = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "udp_send");
169 if (!method) {
170 DEBUG_WARNING("alloc: BIO_meth_new() failed\n");
171 ERR_clear_error();
172 return NULL;
173 }
174
175 BIO_meth_set_write(method, bio_write);
176 BIO_meth_set_ctrl(method, bio_ctrl);
177 BIO_meth_set_create(method, bio_create);
178 BIO_meth_set_destroy(method, bio_destroy);
179
180 return method;
181}
182
183#else
184
185static struct bio_method_st bio_udp_send = {
186 BIO_TYPE_SOURCE_SINK,
187 "udp_send",
188 bio_write,
189 0,
190 0,
191 0,
192 bio_ctrl,
193 bio_create,
194 bio_destroy,
195 0
196};
197
198#endif
199
200
201static void tls_close(struct tls_conn *tc)
202{
203 int r;
204
205 if (!tc->ssl)
206 return;
207
208 r = SSL_shutdown(tc->ssl);
209 if (r <= 0)
210 ERR_clear_error();
211
212 SSL_free(tc->ssl);
213 tc->ssl = NULL;
214}
215
216
217static void conn_destructor(void *arg)
218{
219 struct tls_conn *tc = arg;
220
221 hash_unlink(&tc->he);
222 tmr_cancel(&tc->tmr);
223 tls_close(tc);
224
225#ifdef TLS_BIO_OPAQUE
226 if (tc->biomet)
227 BIO_meth_free(tc->biomet);
228#endif
229
230 mem_deref(tc->sock);
231}
232
233
234static void conn_close(struct tls_conn *tc, int err)
235{
236 tmr_cancel(&tc->tmr);
237 tls_close(tc);
238 tc->up = false;
239
240 if (tc->closeh)
241 tc->closeh(err, tc->arg);
242}
243
244
245#if defined (DTLS_CTRL_HANDLE_TIMEOUT) && defined(DTLS_CTRL_GET_TIMEOUT)
246
247static void check_timer(struct tls_conn *tc);
248
249
250static void timeout(void *arg)
251{
252 struct tls_conn *tc = arg;
253
254 DEBUG_INFO("timeout\n");
255
256 if (0 <= DTLSv1_handle_timeout(tc->ssl)) {
257
258 check_timer(tc);
259 }
260 else {
261 ERR_clear_error();
262 conn_close(tc, ETIMEDOUT);
263 }
264}
265
266
267static void check_timer(struct tls_conn *tc)
268{
269 struct timeval tv = {0, 0};
270
271 if (1 == DTLSv1_get_timeout(tc->ssl, &tv)) {
272
273 tmr_start(&tc->tmr, tv.tv_sec * 1000 + tv.tv_usec / 1000,
274 timeout, tc);
275 }
276 else {
277 tmr_cancel(&tc->tmr);
278 }
279}
280
281#else
282
283static void check_timer(struct tls_conn *tc)
284{
285 (void)tc;
286}
287
288#endif
289
290
291static int tls_connect(struct tls_conn *tc)
292{
293 int r;
294
295 ERR_clear_error();
296
297 r = SSL_connect(tc->ssl);
298 if (r <= 0) {
299 const int ssl_err = SSL_get_error(tc->ssl, r);
300
301 tls_flush_error();
302
303 switch (ssl_err) {
304
305 case SSL_ERROR_WANT_READ:
306 break;
307
308 default:
309 DEBUG_WARNING("connect error: %i\n", ssl_err);
310 return EPROTO;
311 }
312 }
313
314 check_timer(tc);
315
316 return 0;
317}
318
319
320static int tls_accept(struct tls_conn *tc)
321{
322 int r;
323
324 ERR_clear_error();
325
326 r = SSL_accept(tc->ssl);
327 if (r <= 0) {
328 const int ssl_err = SSL_get_error(tc->ssl, r);
329
330 tls_flush_error();
331
332 switch (ssl_err) {
333
334 case SSL_ERROR_WANT_READ:
335 break;
336
337 default:
338 DEBUG_WARNING("accept error: %i\n", ssl_err);
339 return EPROTO;
340 }
341 }
342
343 check_timer(tc);
344
345 return 0;
346}
347
348
349static void conn_recv(struct tls_conn *tc, struct mbuf *mb)
350{
351 int err, r;
352
353 if (!tc->ssl)
354 return;
355
356 /* feed SSL data to the BIO */
357 r = BIO_write(tc->sbio_in, mbuf_buf(mb), (int)mbuf_get_left(mb));
358 if (r <= 0) {
359 DEBUG_WARNING("receive bio write error: %i\n", r);
360 ERR_clear_error();
361 conn_close(tc, ENOMEM);
362 return;
363 }
364
365 if (SSL_state(tc->ssl) != SSL_ST_OK) {
366
367 if (tc->up) {
368 conn_close(tc, EPROTO);
369 return;
370 }
371
372 if (tc->active) {
373 err = tls_connect(tc);
374 }
375 else {
376 err = tls_accept(tc);
377 }
378
379 if (err) {
380 conn_close(tc, err);
381 return;
382 }
383
384 DEBUG_INFO("%s: state=0x%04x\n",
385 tc->active ? "client" : "server",
386 SSL_state(tc->ssl));
387
388 /* TLS connection is established */
389 if (SSL_state(tc->ssl) != SSL_ST_OK)
390 return;
391
392 tc->up = true;
393
394 if (tc->estabh) {
395 uint32_t nrefs;
396
397 mem_ref(tc);
398
399 tc->estabh(tc->arg);
400
401 nrefs = mem_nrefs(tc);
402 mem_deref(tc);
403
404 /* check if connection was deref'd from handler */
405 if (nrefs == 1)
406 return;
407 }
408 }
409
410 mbuf_set_pos(mb, 0);
411
412 for (;;) {
413 int n;
414
415 if (mbuf_get_space(mb) < 4096) {
416 err = mbuf_resize(mb, mb->size + 8192);
417 if (err) {
418 conn_close(tc, err);
419 return;
420 }
421 }
422
423 ERR_clear_error();
424
425 n = SSL_read(tc->ssl, mbuf_buf(mb), (int)mbuf_get_space(mb));
426 if (n <= 0) {
427 const int ssl_err = SSL_get_error(tc->ssl, n);
428
429 ERR_clear_error();
430
431 switch (ssl_err) {
432
433 case SSL_ERROR_WANT_READ:
434 break;
435
436 case SSL_ERROR_ZERO_RETURN:
437 conn_close(tc, ECONNRESET);
438 return;
439
440 default:
441 DEBUG_WARNING("read error: %i\n", ssl_err);
442 conn_close(tc, EPROTO);
443 return;
444 }
445
446 break;
447 }
448
449 mb->pos += n;
450 }
451
452 mbuf_set_end(mb, mb->pos);
453 mbuf_set_pos(mb, 0);
454
455 if (tc->recvh && mbuf_get_left(mb) > 0)
456 tc->recvh(mb, tc->arg);
457
458 return;
459}
460
461
462static int conn_alloc(struct tls_conn **ptc, struct tls *tls,
463 struct dtls_sock *sock, const struct sa *peer,
464 dtls_estab_h *estabh, dtls_recv_h *recvh,
465 dtls_close_h *closeh, void *arg)
466{
467 struct tls_conn *tc;
468 int err = 0;
469
470 tc = mem_zalloc(sizeof(*tc), conn_destructor);
471 if (!tc)
472 return ENOMEM;
473
474 hash_append(sock->ht, sa_hash(peer, SA_ALL), &tc->he, tc);
475
476 tc->sock = mem_ref(sock);
477 tc->peer = *peer;
478 tc->estabh = estabh;
479 tc->recvh = recvh;
480 tc->closeh = closeh;
481 tc->arg = arg;
482
483#ifdef TLS_BIO_OPAQUE
484 tc->biomet = bio_method_udp();
485 if (!tc->biomet) {
486 err = ENOMEM;
487 goto out;
488 }
489#endif
490
491 /* Connect the SSL socket */
492 tc->ssl = SSL_new(tls->ctx);
493 if (!tc->ssl) {
494 DEBUG_WARNING("ssl new failed: %i\n",
495 ERR_GET_REASON(ERR_get_error()));
496 ERR_clear_error();
497 err = ENOMEM;
498 goto out;
499 }
500
501 tc->sbio_in = BIO_new(BIO_s_mem());
502 if (!tc->sbio_in) {
503 ERR_clear_error();
504 err = ENOMEM;
505 goto out;
506 }
507
508#ifdef TLS_BIO_OPAQUE
509 tc->sbio_out = BIO_new(tc->biomet);
510#else
511 tc->sbio_out = BIO_new(&bio_udp_send);
512#endif
513 if (!tc->sbio_out) {
514 ERR_clear_error();
515 BIO_free(tc->sbio_in);
516 err = ENOMEM;
517 goto out;
518 }
519
520#ifdef TLS_BIO_OPAQUE
521 BIO_set_data(tc->sbio_out, tc);
522#else
523 tc->sbio_out->ptr = tc;
524#endif
525
526 SSL_set_bio(tc->ssl, tc->sbio_in, tc->sbio_out);
527
528 SSL_set_read_ahead(tc->ssl, 1);
529
530 out:
531 if (err)
532 mem_deref(tc);
533 else
534 *ptc = tc;
535
536 return err;
537}
538
539
540/**
541 * DTLS Connect
542 *
543 * @param ptc Pointer to allocated DTLS connection
544 * @param tls TLS Context
545 * @param sock DTLS Socket
546 * @param peer Peer address
547 * @param estabh Establish handler
548 * @param recvh Receive handler
549 * @param closeh Close handler
550 * @param arg Handler argument
551 *
552 * @return 0 if success, otherwise errorcode
553 */
554int dtls_connect(struct tls_conn **ptc, struct tls *tls,
555 struct dtls_sock *sock, const struct sa *peer,
556 dtls_estab_h *estabh, dtls_recv_h *recvh,
557 dtls_close_h *closeh, void *arg)
558{
559 struct tls_conn *tc;
560 int err;
561
562 if (!ptc || !tls || !sock || !peer)
563 return EINVAL;
564
565 err = conn_alloc(&tc, tls, sock, peer, estabh, recvh, closeh, arg);
566 if (err)
567 return err;
568
569 tc->active = true;
570
571 err = tls_connect(tc);
572 if (err)
573 goto out;
574
575 out:
576 if (err)
577 mem_deref(tc);
578 else
579 *ptc = tc;
580
581 return err;
582}
583
584
585/**
586 * DTLS Accept
587 *
588 * @param ptc Pointer to allocated DTLS connection
589 * @param tls TLS Context
590 * @param sock DTLS Socket
591 * @param estabh Establish handler
592 * @param recvh Receive handler
593 * @param closeh Close handler
594 * @param arg Handler argument
595 *
596 * @return 0 if success, otherwise errorcode
597 */
598int dtls_accept(struct tls_conn **ptc, struct tls *tls,
599 struct dtls_sock *sock,
600 dtls_estab_h *estabh, dtls_recv_h *recvh,
601 dtls_close_h *closeh, void *arg)
602{
603 struct tls_conn *tc;
604 int err, r;
605
606 if (!ptc || !tls || !sock || !sock->mb)
607 return EINVAL;
608
609 err = conn_alloc(&tc, tls, sock, &sock->peer, estabh, recvh, closeh,
610 arg);
611 if (err)
612 return err;
613
614 tc->active = false;
615
616 r = BIO_write(tc->sbio_in, mbuf_buf(sock->mb),
617 (int)mbuf_get_left(sock->mb));
618 if (r <= 0) {
619 DEBUG_WARNING("accept bio write error: %i\n", r);
620 ERR_clear_error();
621 err = ENOMEM;
622 goto out;
623 }
624
625 err = tls_accept(tc);
626 if (err)
627 goto out;
628
629 sock->mb = mem_deref(sock->mb);
630
631 out:
632 if (err)
633 mem_deref(tc);
634 else
635 *ptc = tc;
636
637 return err;
638}
639
640
641/**
642 * Send data on a DTLS connection
643 *
644 * @param tc DTLS connection
645 * @param mb Buffer to send
646 *
647 * @return 0 if success, otherwise errorcode
648 */
649int dtls_send(struct tls_conn *tc, struct mbuf *mb)
650{
651 int r;
652
653 if (!tc || !mb)
654 return EINVAL;
655
656 if (!tc->up || !tc->ssl)
657 return ENOTCONN;
658
659 ERR_clear_error();
660
661 r = SSL_write(tc->ssl, mbuf_buf(mb), (int)mbuf_get_left(mb));
662 if (r <= 0) {
663 DEBUG_WARNING("write error: %i\n", SSL_get_error(tc->ssl, r));
664 ERR_clear_error();
665 return EPROTO;
666 }
667
668 return 0;
669}
670
671
672/**
673 * Set handlers on a DTLS Connection
674 *
675 * @param tc DTLS Connection
676 * @param estabh DTLS Connection Established handler
677 * @param recvh DTLS Connection Receive data handler
678 * @param closeh DTLS Connection Close handler
679 * @param arg Handler argument
680 */
681void dtls_set_handlers(struct tls_conn *tc, dtls_estab_h *estabh,
682 dtls_recv_h *recvh, dtls_close_h *closeh, void *arg)
683{
684 if (!tc)
685 return;
686
687 tc->estabh = estabh;
688 tc->recvh = recvh;
689 tc->closeh = closeh;
690 tc->arg = arg;
691}
692
693
694/**
695 * Get the remote peer of a DTLS Connection
696 *
697 * @param tc DTLS Connection
698 *
699 * @return Remote peer
700 */
701const struct sa *dtls_peer(const struct tls_conn *tc)
702{
703 return tc ? &tc->peer : NULL;
704}
705
706
707/**
708 * Set the remote peer of a DTLS Connection
709 *
710 * @param tc DTLS Connection
711 * @param peer Peer address
712 */
713void dtls_set_peer(struct tls_conn *tc, const struct sa *peer)
714{
715 if (!tc || !peer)
716 return;
717
718 hash_unlink(&tc->he);
719 hash_append(tc->sock->ht, sa_hash(peer, SA_ALL), &tc->he, tc);
720
721 tc->peer = *peer;
722}
723
724
725static void sock_destructor(void *arg)
726{
727 struct dtls_sock *sock = arg;
728
729 hash_clear(sock->ht);
730 mem_deref(sock->uh);
731 mem_deref(sock->us);
732 mem_deref(sock->ht);
733 mem_deref(sock->mb);
734}
735
736
737static bool cmp_handler(struct le *le, void *arg)
738{
739 struct tls_conn *tc = le->data;
740
741 return sa_cmp(&tc->peer, arg, SA_ALL);
742}
743
744
745static struct tls_conn *conn_lookup(struct dtls_sock *sock,
746 const struct sa *peer)
747{
748 return list_ledata(hash_lookup(sock->ht, sa_hash(peer, SA_ALL),
749 cmp_handler, (void *)peer));
750}
751
752
753static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg)
754{
755 struct dtls_sock *sock = arg;
756 struct tls_conn *tc;
757 uint8_t b;
758
759 if (mbuf_get_left(mb) < 1)
760 return false;
761
762 b = mb->buf[mb->pos];
763 if (b < 20 || b > 63)
764 return false;
765
766 tc = conn_lookup(sock, src);
767 if (tc) {
768 conn_recv(tc, mb);
769 return true;
770 }
771
772 if (sock->connh) {
773
774 mem_deref(sock->mb);
775 sock->mb = mem_ref(mb);
776 sock->peer = *src;
777
778 sock->connh(src, sock->arg);
779 }
780
781 return true;
782}
783
784
785/**
786 * Create DTLS Socket
787 *
788 * @param sockp Pointer to returned DTLS Socket
789 * @param laddr Local listen address (optional)
790 * @param us External UDP socket (optional)
791 * @param htsize Connection hash table size
792 * @param layer UDP protocol layer
793 * @param connh Connect handler
794 * @param arg Handler argument
795 *
796 * @return 0 if success, otherwise errorcode
797 */
798int dtls_listen(struct dtls_sock **sockp, const struct sa *laddr,
799 struct udp_sock *us, uint32_t htsize, int layer,
800 dtls_conn_h *connh, void *arg)
801{
802 struct dtls_sock *sock;
803 int err;
804
805 if (!sockp)
806 return EINVAL;
807
808 sock = mem_zalloc(sizeof(*sock), sock_destructor);
809 if (!sock)
810 return ENOMEM;
811
812 if (us) {
813 sock->us = mem_ref(us);
814 }
815 else {
816 err = udp_listen(&sock->us, laddr, NULL, NULL);
817 if (err)
818 goto out;
819 }
820
821 err = udp_register_helper(&sock->uh, sock->us, layer,
822 NULL, recv_handler, sock);
823 if (err)
824 goto out;
825
826 err = hash_alloc(&sock->ht, hash_valid_size(htsize));
827 if (err)
828 goto out;
829
830 sock->mtu = MTU_DEFAULT;
831 sock->connh = connh;
832 sock->arg = arg;
833
834 out:
835 if (err)
836 mem_deref(sock);
837 else
838 *sockp = sock;
839
840 return err;
841}
842
843
844/**
845 * Get the underlying UDP socket of a DTLS Socket
846 *
847 * @param sock DTLS Socket
848 *
849 * @return UDP Socket
850 */
851struct udp_sock *dtls_udp_sock(struct dtls_sock *sock)
852{
853 return sock ? sock->us : NULL;
854}
855
856
857/**
858 * Set MTU on a DTLS Socket
859 *
860 * @param sock DTLS Socket
861 * @param mtu MTU value
862 */
863void dtls_set_mtu(struct dtls_sock *sock, size_t mtu)
864{
865 if (!sock)
866 return;
867
868 sock->mtu = mtu;
869}
870
871
872void dtls_recv_packet(struct dtls_sock *sock, const struct sa *src,
873 struct mbuf *mb)
874{
875 struct sa addr;
876
877 if (!sock || !src || !mb)
878 return;
879
880 addr = *src;
881
882 recv_handler(&addr, mb, sock);
883}