1 /*
2 * Copyright (C) 2009-2012 Free Software Foundation, Inc.
3 * Copyright (C) 2013 Nikos Mavrogiannopoulos
4 *
5 * Authors: Jonathan Bastien-Filiatrault
6 * Nikos Mavrogiannopoulos
7 *
8 * This file is part of GNUTLS.
9 *
10 * The GNUTLS library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1 of
13 * the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>
22 *
23 */
24
25 /* Functions that relate to DTLS retransmission and reassembly.
26 */
27
28 #include "gnutls_int.h"
29 #include "errors.h"
30 #include "debug.h"
31 #include "dtls.h"
32 #include "record.h"
33 #include <mbuffers.h>
34 #include <buffers.h>
35 #include <constate.h>
36 #include <state.h>
37 #include <gnutls/dtls.h>
38 #include <algorithms.h>
39
_dtls_async_timer_delete(gnutls_session_t session)40 void _dtls_async_timer_delete(gnutls_session_t session)
41 {
42 if (session->internals.dtls.async_term != 0) {
43 _gnutls_dtls_log
44 ("DTLS[%p]: Deinitializing previous handshake state.\n",
45 session);
46 session->internals.dtls.async_term = 0; /* turn off "timer" */
47
48 _dtls_reset_hsk_state(session);
49 _gnutls_handshake_io_buffer_clear(session);
50 _gnutls_epoch_gc(session);
51 }
52 }
53
54 /* This function fragments and transmits a previously buffered
55 * outgoing message. It accepts mtu_data which is a buffer to
56 * be reused (should be set to NULL initially).
57 */
58 static inline int
transmit_message(gnutls_session_t session,mbuffer_st * bufel,uint8_t ** buf)59 transmit_message(gnutls_session_t session,
60 mbuffer_st * bufel, uint8_t ** buf)
61 {
62 uint8_t *data, *mtu_data;
63 int ret = 0;
64 unsigned int offset, frag_len, data_size;
65 unsigned int mtu =
66 gnutls_dtls_get_data_mtu(session);
67
68 if (session->security_parameters.max_record_send_size < mtu)
69 mtu = session->security_parameters.max_record_send_size;
70
71 mtu -= DTLS_HANDSHAKE_HEADER_SIZE;
72
73 if (bufel->type == GNUTLS_CHANGE_CIPHER_SPEC) {
74 _gnutls_dtls_log
75 ("DTLS[%p]: Sending Packet[%u] fragment %s(%d), mtu %u\n",
76 session, bufel->handshake_sequence,
77 _gnutls_handshake2str(bufel->htype), bufel->htype, mtu);
78
79 return _gnutls_send_int(session, bufel->type, -1,
80 bufel->epoch,
81 _mbuffer_get_uhead_ptr(bufel),
82 _mbuffer_get_uhead_size(bufel), 0);
83 }
84
85 if (*buf == NULL)
86 *buf = gnutls_malloc(mtu + DTLS_HANDSHAKE_HEADER_SIZE);
87 if (*buf == NULL)
88 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
89
90 mtu_data = *buf;
91
92 data = _mbuffer_get_udata_ptr(bufel);
93 data_size = _mbuffer_get_udata_size(bufel);
94
95 /* Write fixed headers
96 */
97
98 /* Handshake type */
99 mtu_data[0] = (uint8_t) bufel->htype;
100
101 /* Total length */
102 _gnutls_write_uint24(data_size, &mtu_data[1]);
103
104 /* Handshake sequence */
105 _gnutls_write_uint16(bufel->handshake_sequence, &mtu_data[4]);
106
107 /* Chop up and send handshake message into mtu-size pieces. */
108 for (offset = 0; offset <= data_size; offset += mtu) {
109 /* Calculate fragment length */
110 if (offset + mtu > data_size)
111 frag_len = data_size - offset;
112 else
113 frag_len = mtu;
114
115 /* we normally allow fragments of zero length, to allow
116 * the packets which have zero size. On the others don't
117 * send such fragments */
118 if (frag_len == 0 && data_size > 0) {
119 ret = 0;
120 break;
121 }
122
123 /* Fragment offset */
124 _gnutls_write_uint24(offset, &mtu_data[6]);
125
126 /* Fragment length */
127 _gnutls_write_uint24(frag_len, &mtu_data[9]);
128
129 memcpy(&mtu_data[DTLS_HANDSHAKE_HEADER_SIZE],
130 data + offset, frag_len);
131
132 _gnutls_dtls_log
133 ("DTLS[%p]: Sending Packet[%u] fragment %s(%d) with "
134 "length: %u, offset: %u, fragment length: %u, mtu: %u\n",
135 session, bufel->handshake_sequence,
136 _gnutls_handshake2str(bufel->htype), bufel->htype,
137 data_size, offset, frag_len, mtu);
138
139 ret = _gnutls_send_int(session, bufel->type, bufel->htype,
140 bufel->epoch, mtu_data,
141 DTLS_HANDSHAKE_HEADER_SIZE +
142 frag_len, 0);
143 if (ret < 0) {
144 gnutls_assert();
145 break;
146 }
147 }
148
149 return ret;
150 }
151
drop_usage_count(gnutls_session_t session,mbuffer_head_st * const send_buffer)152 static int drop_usage_count(gnutls_session_t session,
153 mbuffer_head_st * const send_buffer)
154 {
155 int ret;
156 mbuffer_st *cur;
157
158 for (cur = send_buffer->head; cur != NULL; cur = cur->next) {
159 ret = _gnutls_epoch_refcount_dec(session, cur->epoch);
160 if (ret < 0)
161 return gnutls_assert_val(ret);
162 }
163
164 return 0;
165 }
166
167
168 /* Checks whether the received packet contains a handshake
169 * packet with sequence higher that the previously received.
170 * It must be called only when an actual packet has been
171 * received.
172 *
173 * Returns: 0 if expected, negative value otherwise.
174 */
is_next_hpacket_expected(gnutls_session_t session)175 static int is_next_hpacket_expected(gnutls_session_t session)
176 {
177 int ret;
178
179 /* htype is arbitrary */
180 ret =
181 _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE,
182 GNUTLS_HANDSHAKE_FINISHED, 0);
183 if (ret < 0)
184 return gnutls_assert_val(ret);
185
186 ret = _gnutls_parse_record_buffered_msgs(session);
187 if (ret < 0)
188 return gnutls_assert_val(ret);
189
190 if (session->internals.handshake_recv_buffer_size > 0)
191 return 0;
192 else
193 return
194 gnutls_assert_val
195 (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
196 }
197
_dtls_reset_hsk_state(gnutls_session_t session)198 void _dtls_reset_hsk_state(gnutls_session_t session)
199 {
200 session->internals.dtls.flight_init = 0;
201 drop_usage_count(session,
202 &session->internals.handshake_send_buffer);
203 _mbuffer_head_clear(&session->internals.handshake_send_buffer);
204 }
205
206
207 #define UPDATE_TIMER { \
208 session->internals.dtls.actual_retrans_timeout_ms *= 2; \
209 session->internals.dtls.actual_retrans_timeout_ms %= MAX_DTLS_TIMEOUT; \
210 }
211
212 #define RESET_TIMER \
213 session->internals.dtls.actual_retrans_timeout_ms = session->internals.dtls.retrans_timeout_ms
214
215 #define TIMER_WINDOW session->internals.dtls.actual_retrans_timeout_ms
216
217 /* This function transmits the flight that has been previously
218 * buffered.
219 *
220 * This function is called from the handshake layer and calls the
221 * record layer.
222 */
_dtls_transmit(gnutls_session_t session)223 int _dtls_transmit(gnutls_session_t session)
224 {
225 int ret;
226 uint8_t *buf = NULL;
227 unsigned int timeout;
228
229 /* PREPARING -> SENDING state transition */
230 mbuffer_head_st *const send_buffer =
231 &session->internals.handshake_send_buffer;
232 mbuffer_st *cur;
233 gnutls_handshake_description_t last_type = 0;
234 unsigned int diff;
235 struct timespec now;
236
237 gnutls_gettime(&now);
238
239 /* If we have already sent a flight and we are operating in a
240 * non blocking way, check if it is time to retransmit or just
241 * return.
242 */
243 if (session->internals.dtls.flight_init != 0
244 && (session->internals.flags & GNUTLS_NONBLOCK)) {
245 /* just in case previous run was interrupted */
246 ret = _gnutls_io_write_flush(session);
247 if (ret < 0) {
248 gnutls_assert();
249 goto cleanup;
250 }
251
252 if (session->internals.dtls.last_flight == 0
253 || !_dtls_is_async(session)) {
254 /* check for ACK */
255 ret = _gnutls_io_check_recv(session, 0);
256 if (ret == GNUTLS_E_TIMEDOUT) {
257 /* if no retransmission is required yet just return
258 */
259 if (timespec_sub_ms
260 (&now,
261 &session->internals.dtls.
262 last_retransmit) < TIMER_WINDOW) {
263 gnutls_assert();
264 goto nb_timeout;
265 }
266 } else { /* received something */
267
268 if (ret == 0) {
269 ret =
270 is_next_hpacket_expected
271 (session);
272 if (ret == GNUTLS_E_AGAIN
273 || ret == GNUTLS_E_INTERRUPTED)
274 goto nb_timeout;
275 if (ret < 0
276 && ret !=
277 GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET)
278 {
279 gnutls_assert();
280 goto cleanup;
281 }
282 if (ret == 0)
283 goto end_flight;
284 /* if ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET retransmit */
285 } else
286 goto nb_timeout;
287 }
288 }
289 }
290
291 do {
292 timeout = TIMER_WINDOW;
293
294 diff =
295 timespec_sub_ms(&now,
296 &session->internals.handshake_start_time);
297 if (diff >= session->internals.handshake_timeout_ms) {
298 _gnutls_dtls_log("Session timeout: %u ms\n", diff);
299 ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
300 goto end_flight;
301 }
302
303 diff =
304 timespec_sub_ms(&now,
305 &session->internals.dtls.
306 last_retransmit);
307 if (session->internals.dtls.flight_init == 0
308 || diff >= TIMER_WINDOW) {
309 _gnutls_dtls_log
310 ("DTLS[%p]: %sStart of flight transmission.\n",
311 session,
312 (session->internals.dtls.flight_init ==
313 0) ? "" : "re-");
314 for (cur = send_buffer->head; cur != NULL;
315 cur = cur->next) {
316 ret = transmit_message(session, cur, &buf);
317 if (ret < 0) {
318 gnutls_assert();
319 goto end_flight;
320 }
321
322 last_type = cur->htype;
323 }
324 gnutls_gettime(&session->internals.dtls.last_retransmit);
325
326 if (session->internals.dtls.flight_init == 0) {
327 session->internals.dtls.flight_init = 1;
328 RESET_TIMER;
329 timeout = TIMER_WINDOW;
330
331 if (last_type == GNUTLS_HANDSHAKE_FINISHED) {
332 /* On the last flight we cannot ensure retransmission
333 * from here. _dtls_wait_and_retransmit() is being called
334 * by handshake.
335 */
336 session->internals.dtls.
337 last_flight = 1;
338 } else
339 session->internals.dtls.
340 last_flight = 0;
341 } else {
342 UPDATE_TIMER;
343 }
344 }
345
346 ret = _gnutls_io_write_flush(session);
347 if (ret < 0) {
348 ret = gnutls_assert_val(ret);
349 goto cleanup;
350 }
351
352 /* last message in handshake -> no ack */
353 if (session->internals.dtls.last_flight != 0) {
354 /* we don't wait here. We just return 0 and
355 * if a retransmission occurs because peer didn't receive it
356 * we rely on the record or handshake
357 * layer calling this function again.
358 */
359 ret = 0;
360 goto cleanup;
361 } else { /* all other messages -> implicit ack (receive of next flight) */
362
363 if (!(session->internals.flags & GNUTLS_NONBLOCK))
364 ret =
365 _gnutls_io_check_recv(session,
366 timeout);
367 else {
368 ret = _gnutls_io_check_recv(session, 0);
369 if (ret == GNUTLS_E_TIMEDOUT) {
370 goto nb_timeout;
371 }
372 }
373
374 if (ret == 0) {
375 ret = is_next_hpacket_expected(session);
376 if (ret == GNUTLS_E_AGAIN
377 || ret == GNUTLS_E_INTERRUPTED)
378 goto nb_timeout;
379
380 if (ret ==
381 GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET) {
382 ret = GNUTLS_E_TIMEDOUT;
383 goto keep_up;
384 }
385 if (ret < 0) {
386 gnutls_assert();
387 goto cleanup;
388 }
389 goto end_flight;
390 }
391 }
392
393 keep_up:
394 gnutls_gettime(&now);
395 } while (ret == GNUTLS_E_TIMEDOUT);
396
397 if (ret < 0) {
398 ret = gnutls_assert_val(ret);
399 goto end_flight;
400 }
401
402 ret = 0;
403
404 end_flight:
405 _gnutls_dtls_log("DTLS[%p]: End of flight transmission.\n",
406 session);
407 _dtls_reset_hsk_state(session);
408
409 cleanup:
410 if (buf != NULL)
411 gnutls_free(buf);
412
413 /* SENDING -> WAITING state transition */
414 return ret;
415
416 nb_timeout:
417 if (buf != NULL)
418 gnutls_free(buf);
419
420 RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, ret);
421 }
422
423 /* Waits for the last flight or retransmits
424 * the previous on timeout. Returns 0 on success.
425 */
_dtls_wait_and_retransmit(gnutls_session_t session)426 int _dtls_wait_and_retransmit(gnutls_session_t session)
427 {
428 int ret;
429
430 if (!(session->internals.flags & GNUTLS_NONBLOCK))
431 ret = _gnutls_io_check_recv(session, TIMER_WINDOW);
432 else
433 ret = _gnutls_io_check_recv(session, 0);
434
435 if (ret == GNUTLS_E_TIMEDOUT) {
436 ret = _dtls_retransmit(session);
437 if (ret == 0) {
438 RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, 0);
439 } else
440 return gnutls_assert_val(ret);
441 }
442
443 RESET_TIMER;
444 return 0;
445 }
446
447 /**
448 * gnutls_dtls_set_timeouts:
449 * @session: is a #gnutls_session_t type.
450 * @retrans_timeout: The time at which a retransmission will occur in milliseconds
451 * @total_timeout: The time at which the connection will be aborted, in milliseconds.
452 *
453 * This function will set the timeouts required for the DTLS handshake
454 * protocol. The retransmission timeout is the time after which a
455 * message from the peer is not received, the previous messages will
456 * be retransmitted. The total timeout is the time after which the
457 * handshake will be aborted with %GNUTLS_E_TIMEDOUT.
458 *
459 * The DTLS protocol recommends the values of 1 sec and 60 seconds
460 * respectively, and these are the default values.
461 *
462 * To disable retransmissions set a @retrans_timeout larger than the @total_timeout.
463 *
464 * Since: 3.0
465 **/
gnutls_dtls_set_timeouts(gnutls_session_t session,unsigned int retrans_timeout,unsigned int total_timeout)466 void gnutls_dtls_set_timeouts(gnutls_session_t session,
467 unsigned int retrans_timeout,
468 unsigned int total_timeout)
469 {
470 if (total_timeout == GNUTLS_INDEFINITE_TIMEOUT)
471 session->internals.handshake_timeout_ms = 0;
472 else
473 session->internals.handshake_timeout_ms = total_timeout;
474
475 session->internals.dtls.retrans_timeout_ms = retrans_timeout;
476 }
477
478 /**
479 * gnutls_dtls_set_mtu:
480 * @session: is a #gnutls_session_t type.
481 * @mtu: The maximum transfer unit of the transport
482 *
483 * This function will set the maximum transfer unit of the transport
484 * that DTLS packets are sent over. Note that this should exclude
485 * the IP (or IPv6) and UDP headers. So for DTLS over IPv6 on an
486 * Ethernet device with MTU 1500, the DTLS MTU set with this function
487 * would be 1500 - 40 (IPV6 header) - 8 (UDP header) = 1452.
488 *
489 * Since: 3.0
490 **/
gnutls_dtls_set_mtu(gnutls_session_t session,unsigned int mtu)491 void gnutls_dtls_set_mtu(gnutls_session_t session, unsigned int mtu)
492 {
493 session->internals.dtls.mtu = MIN(mtu, DEFAULT_MAX_RECORD_SIZE);
494 }
495
496 /* when max is non-zero this function will return the maximum
497 * overhead that this ciphersuite may introduce, e.g., the maximum
498 * amount of padding required */
_gnutls_record_overhead(const version_entry_st * ver,const cipher_entry_st * cipher,const mac_entry_st * mac,unsigned max)499 unsigned _gnutls_record_overhead(const version_entry_st *ver,
500 const cipher_entry_st *cipher,
501 const mac_entry_st *mac,
502 unsigned max)
503 {
504 int total = 0;
505 int ret;
506 int hash_len = 0;
507
508 if (unlikely(cipher == NULL))
509 return 0;
510
511 /* 1 octet content type in the unencrypted content */
512 if (ver->tls13_sem)
513 total++;
514
515 if (mac->id == GNUTLS_MAC_AEAD) {
516 if (!ver->tls13_sem)
517 total += _gnutls_cipher_get_explicit_iv_size(cipher);
518
519 total += _gnutls_cipher_get_tag_size(cipher);
520 } else {
521 /* STREAM + BLOCK have a MAC appended */
522 ret = _gnutls_mac_get_algo_len(mac);
523 if (unlikely(ret < 0))
524 return 0;
525
526 hash_len = ret;
527 total += hash_len;
528 }
529
530 /* Block ciphers have padding + IV */
531 if (_gnutls_cipher_type(cipher) == CIPHER_BLOCK) {
532 int exp_iv;
533
534 exp_iv = _gnutls_cipher_get_explicit_iv_size(cipher);
535
536 if (max)
537 total += 2*exp_iv; /* block == iv size */
538 else
539 total += exp_iv + 1;
540 }
541
542 return total;
543 }
544
545 /**
546 * gnutls_est_record_overhead_size:
547 * @version: is a #gnutls_protocol_t value
548 * @cipher: is a #gnutls_cipher_algorithm_t value
549 * @mac: is a #gnutls_mac_algorithm_t value
550 * @comp: is a #gnutls_compression_method_t value (ignored)
551 * @flags: must be zero
552 *
553 * This function will return the set size in bytes of the overhead
554 * due to TLS (or DTLS) per record.
555 *
556 * Note that this function may provide inaccurate values when TLS
557 * extensions that modify the record format are negotiated. In these
558 * cases a more accurate value can be obtained using gnutls_record_overhead_size()
559 * after a completed handshake.
560 *
561 * Since: 3.2.2
562 **/
gnutls_est_record_overhead_size(gnutls_protocol_t version,gnutls_cipher_algorithm_t cipher,gnutls_mac_algorithm_t mac,gnutls_compression_method_t comp,unsigned int flags)563 size_t gnutls_est_record_overhead_size(gnutls_protocol_t version,
564 gnutls_cipher_algorithm_t cipher,
565 gnutls_mac_algorithm_t mac,
566 gnutls_compression_method_t comp,
567 unsigned int flags)
568 {
569 const cipher_entry_st *c;
570 const mac_entry_st *m;
571 const version_entry_st *v;
572 size_t total = 0;
573
574 c = cipher_to_entry(cipher);
575 if (c == NULL)
576 return 0;
577
578 m = mac_to_entry(mac);
579 if (m == NULL)
580 return 0;
581
582 v = version_to_entry(version);
583 if (v == NULL)
584 return 0;
585
586 if (v->transport == GNUTLS_STREAM)
587 total = TLS_RECORD_HEADER_SIZE;
588 else
589 total = DTLS_RECORD_HEADER_SIZE;
590
591 total += _gnutls_record_overhead(v, c, m, 1);
592
593 return total;
594 }
595
596 /* returns overhead imposed by the record layer (encryption/compression)
597 * etc. It does not include the record layer headers, since the caller
598 * needs to cope with rounding to multiples of blocksize, and the header
599 * is outside that.
600 *
601 * blocksize: will contain the block size when padding may be required or 1
602 *
603 * It may return a negative error code on error.
604 */
record_overhead_rt(gnutls_session_t session)605 static int record_overhead_rt(gnutls_session_t session)
606 {
607 record_parameters_st *params;
608 int ret;
609
610 if (session->internals.initial_negotiation_completed == 0)
611 return GNUTLS_E_INVALID_REQUEST;
612 ret = _gnutls_epoch_get(session, EPOCH_WRITE_CURRENT, ¶ms);
613 if (ret < 0)
614 return gnutls_assert_val(ret);
615
616 return _gnutls_record_overhead(get_version(session), params->cipher, params->mac, 1);
617 }
618
619 /**
620 * gnutls_record_overhead_size:
621 * @session: is #gnutls_session_t
622 *
623 * This function will return the size in bytes of the overhead
624 * due to TLS (or DTLS) per record. On certain occasions
625 * (e.g., CBC ciphers) the returned value is the maximum
626 * possible overhead.
627 *
628 * Since: 3.2.2
629 **/
gnutls_record_overhead_size(gnutls_session_t session)630 size_t gnutls_record_overhead_size(gnutls_session_t session)
631 {
632 const version_entry_st *v = get_version(session);
633 int ret;
634 size_t total;
635
636 if (v->transport == GNUTLS_STREAM)
637 total = TLS_RECORD_HEADER_SIZE;
638 else
639 total = DTLS_RECORD_HEADER_SIZE;
640
641 ret = record_overhead_rt(session);
642 if (ret >= 0)
643 total += ret;
644
645 return total;
646 }
647
648
649
650 /**
651 * gnutls_dtls_get_data_mtu:
652 * @session: is a #gnutls_session_t type.
653 *
654 * This function will return the actual maximum transfer unit for
655 * application data. I.e. DTLS headers are subtracted from the
656 * actual MTU which is set using gnutls_dtls_set_mtu().
657 *
658 * Returns: the maximum allowed transfer unit.
659 *
660 * Since: 3.0
661 **/
gnutls_dtls_get_data_mtu(gnutls_session_t session)662 unsigned int gnutls_dtls_get_data_mtu(gnutls_session_t session)
663 {
664 int mtu = session->internals.dtls.mtu;
665 record_parameters_st *params;
666 int ret, k, hash_size, block;
667
668 mtu -= RECORD_HEADER_SIZE(session);
669
670 if (session->internals.initial_negotiation_completed == 0)
671 return mtu;
672
673 ret = _gnutls_epoch_get(session, EPOCH_WRITE_CURRENT, ¶ms);
674 if (ret < 0)
675 return mtu;
676
677 if (params->cipher->type == CIPHER_AEAD || params->cipher->type == CIPHER_STREAM)
678 return mtu-_gnutls_record_overhead(get_version(session), params->cipher, params->mac, 0);
679
680 /* CIPHER_BLOCK: in CBC ciphers guess the data MTU as it depends on residues
681 */
682 hash_size = _gnutls_mac_get_algo_len(params->mac);
683 block = _gnutls_cipher_get_explicit_iv_size(params->cipher);
684 assert(_gnutls_cipher_get_block_size(params->cipher) == block);
685
686 if (params->etm) {
687 /* the maximum data mtu satisfies:
688 * data mtu (mod block) = block-1
689 * or data mtu = (k+1)*(block) - 1
690 *
691 * and data mtu + block + hash size + 1 = link_mtu
692 * (k+2) * (block) + hash size = link_mtu
693 *
694 * We try to find k, and thus data mtu
695 */
696 k = ((mtu-hash_size)/block) - 2;
697
698 return (k+1)*block - 1;
699 } else {
700 /* the maximum data mtu satisfies:
701 * data mtu + hash size (mod block) = block-1
702 * or data mtu = (k+1)*(block) - hash size - 1
703 *
704 * and data mtu + block + hash size + 1 = link_mtu
705 * (k+2) * (block) = link_mtu
706 *
707 * We try to find k, and thus data mtu
708 */
709 k = ((mtu)/block) - 2;
710
711 return (k+1)*block - hash_size - 1;
712 }
713 }
714
715 /**
716 * gnutls_dtls_set_data_mtu:
717 * @session: is a #gnutls_session_t type.
718 * @mtu: The maximum unencrypted transfer unit of the session
719 *
720 * This function will set the maximum size of the *unencrypted* records
721 * which will be sent over a DTLS session. It is equivalent to calculating
722 * the DTLS packet overhead with the current encryption parameters, and
723 * calling gnutls_dtls_set_mtu() with that value. In particular, this means
724 * that you may need to call this function again after any negotiation or
725 * renegotiation, in order to ensure that the MTU is still sufficient to
726 * account for the new protocol overhead.
727 *
728 * In most cases you only need to call gnutls_dtls_set_mtu() with
729 * the maximum MTU of your transport layer.
730 *
731 * Returns: %GNUTLS_E_SUCCESS (0) on success, or a negative error code.
732 *
733 * Since: 3.1
734 **/
gnutls_dtls_set_data_mtu(gnutls_session_t session,unsigned int mtu)735 int gnutls_dtls_set_data_mtu(gnutls_session_t session, unsigned int mtu)
736 {
737 int overhead;
738
739 overhead = record_overhead_rt(session);
740
741 /* You can't call this until the session is actually running */
742 if (overhead < 0)
743 return GNUTLS_E_INVALID_SESSION;
744
745 /* Add the overhead inside the encrypted part */
746 mtu += overhead;
747
748 /* Add the *unencrypted header size */
749 mtu += RECORD_HEADER_SIZE(session);
750
751 gnutls_dtls_set_mtu(session, mtu);
752 return GNUTLS_E_SUCCESS;
753 }
754
755 /**
756 * gnutls_dtls_get_mtu:
757 * @session: is a #gnutls_session_t type.
758 *
759 * This function will return the MTU size as set with
760 * gnutls_dtls_set_mtu(). This is not the actual MTU
761 * of data you can transmit. Use gnutls_dtls_get_data_mtu()
762 * for that reason.
763 *
764 * Returns: the set maximum transfer unit.
765 *
766 * Since: 3.0
767 **/
gnutls_dtls_get_mtu(gnutls_session_t session)768 unsigned int gnutls_dtls_get_mtu(gnutls_session_t session)
769 {
770 return session->internals.dtls.mtu;
771 }
772
773 /**
774 * gnutls_dtls_get_timeout:
775 * @session: is a #gnutls_session_t type.
776 *
777 * This function will return the milliseconds remaining
778 * for a retransmission of the previously sent handshake
779 * message. This function is useful when DTLS is used in
780 * non-blocking mode, to estimate when to call gnutls_handshake()
781 * if no packets have been received.
782 *
783 * Returns: the remaining time in milliseconds.
784 *
785 * Since: 3.0
786 **/
gnutls_dtls_get_timeout(gnutls_session_t session)787 unsigned int gnutls_dtls_get_timeout(gnutls_session_t session)
788 {
789 struct timespec now;
790 unsigned int diff;
791
792 gnutls_gettime(&now);
793
794 diff =
795 timespec_sub_ms(&now,
796 &session->internals.dtls.last_retransmit);
797 if (diff >= TIMER_WINDOW)
798 return 0;
799 else
800 return TIMER_WINDOW - diff;
801 }
802
803 #define COOKIE_SIZE 16
804 #define COOKIE_MAC_SIZE 16
805
806 /* MAC
807 * 16 bytes
808 *
809 * total 19 bytes
810 */
811
812 #define C_HASH GNUTLS_MAC_SHA1
813 #define C_HASH_SIZE 20
814
815 /**
816 * gnutls_dtls_cookie_send:
817 * @key: is a random key to be used at cookie generation
818 * @client_data: contains data identifying the client (i.e. address)
819 * @client_data_size: The size of client's data
820 * @prestate: The previous cookie returned by gnutls_dtls_cookie_verify()
821 * @ptr: A transport pointer to be used by @push_func
822 * @push_func: A function that will be used to reply
823 *
824 * This function can be used to prevent denial of service
825 * attacks to a DTLS server by requiring the client to
826 * reply using a cookie sent by this function. That way
827 * it can be ensured that a client we allocated resources
828 * for (i.e. #gnutls_session_t) is the one that the
829 * original incoming packet was originated from.
830 *
831 * This function must be called at the first incoming packet,
832 * prior to allocating any resources and must be succeeded
833 * by gnutls_dtls_cookie_verify().
834 *
835 * Returns: the number of bytes sent, or a negative error code.
836 *
837 * Since: 3.0
838 **/
gnutls_dtls_cookie_send(gnutls_datum_t * key,void * client_data,size_t client_data_size,gnutls_dtls_prestate_st * prestate,gnutls_transport_ptr_t ptr,gnutls_push_func push_func)839 int gnutls_dtls_cookie_send(gnutls_datum_t * key, void *client_data,
840 size_t client_data_size,
841 gnutls_dtls_prestate_st * prestate,
842 gnutls_transport_ptr_t ptr,
843 gnutls_push_func push_func)
844 {
845 uint8_t hvr[20 + DTLS_HANDSHAKE_HEADER_SIZE + COOKIE_SIZE];
846 int hvr_size = 0, ret;
847 uint8_t digest[C_HASH_SIZE];
848
849 if (key == NULL || key->data == NULL || key->size == 0)
850 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
851
852 /* send
853 * struct {
854 * ContentType type - 1 byte GNUTLS_HANDSHAKE;
855 * ProtocolVersion version; - 2 bytes (254,255)
856 * uint16 epoch; - 2 bytes (0, 0)
857 * uint48 sequence_number; - 4 bytes (0,0,0,0)
858 * uint16 length; - 2 bytes (COOKIE_SIZE+1+2)+DTLS_HANDSHAKE_HEADER_SIZE
859 * uint8_t fragment[DTLSPlaintext.length];
860 * } DTLSPlaintext;
861 *
862 *
863 * struct {
864 * HandshakeType msg_type; 1 byte - GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST
865 * uint24 length; - COOKIE_SIZE+3
866 * uint16 message_seq; - 2 bytes (0,0)
867 * uint24 fragment_offset; - 3 bytes (0,0,0)
868 * uint24 fragment_length; - same as length
869 * }
870 *
871 * struct {
872 * ProtocolVersion server_version;
873 * uint8_t cookie<0..32>;
874 * } HelloVerifyRequest;
875 */
876
877 hvr[hvr_size++] = GNUTLS_HANDSHAKE;
878 /* version */
879 hvr[hvr_size++] = 254;
880 hvr[hvr_size++] = 255;
881
882 /* epoch + seq */
883 memset(&hvr[hvr_size], 0, 8);
884 hvr_size += 7;
885 hvr[hvr_size++] = prestate->record_seq;
886
887 /* length */
888 _gnutls_write_uint16(DTLS_HANDSHAKE_HEADER_SIZE + COOKIE_SIZE + 3,
889 &hvr[hvr_size]);
890 hvr_size += 2;
891
892 /* now handshake headers */
893 hvr[hvr_size++] = GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST;
894 _gnutls_write_uint24(COOKIE_SIZE + 3, &hvr[hvr_size]);
895 hvr_size += 3;
896
897 /* handshake seq */
898 hvr[hvr_size++] = 0;
899 hvr[hvr_size++] = prestate->hsk_write_seq;
900
901 _gnutls_write_uint24(0, &hvr[hvr_size]);
902 hvr_size += 3;
903
904 _gnutls_write_uint24(COOKIE_SIZE + 3, &hvr[hvr_size]);
905 hvr_size += 3;
906
907 /* version */
908 hvr[hvr_size++] = 254;
909 hvr[hvr_size++] = 255;
910 hvr[hvr_size++] = COOKIE_SIZE;
911
912 ret =
913 _gnutls_mac_fast(C_HASH, key->data, key->size, client_data,
914 client_data_size, digest);
915 if (ret < 0)
916 return gnutls_assert_val(ret);
917
918 memcpy(&hvr[hvr_size], digest, COOKIE_MAC_SIZE);
919 hvr_size += COOKIE_MAC_SIZE;
920
921 ret = push_func(ptr, hvr, hvr_size);
922 if (ret < 0)
923 ret = GNUTLS_E_PUSH_ERROR;
924
925 return ret;
926 }
927
928 /**
929 * gnutls_dtls_cookie_verify:
930 * @key: is a random key to be used at cookie generation
931 * @client_data: contains data identifying the client (i.e. address)
932 * @client_data_size: The size of client's data
933 * @_msg: An incoming message that initiates a connection.
934 * @msg_size: The size of the message.
935 * @prestate: The cookie of this client.
936 *
937 * This function will verify the received message for
938 * a valid cookie. If a valid cookie is returned then
939 * it should be associated with the session using
940 * gnutls_dtls_prestate_set();
941 *
942 * This function must be called after gnutls_dtls_cookie_send().
943 *
944 * Returns: %GNUTLS_E_SUCCESS (0) on success, or a negative error code.
945 *
946 * Since: 3.0
947 **/
gnutls_dtls_cookie_verify(gnutls_datum_t * key,void * client_data,size_t client_data_size,void * _msg,size_t msg_size,gnutls_dtls_prestate_st * prestate)948 int gnutls_dtls_cookie_verify(gnutls_datum_t * key,
949 void *client_data, size_t client_data_size,
950 void *_msg, size_t msg_size,
951 gnutls_dtls_prestate_st * prestate)
952 {
953 gnutls_datum_t cookie;
954 int ret;
955 unsigned int pos, sid_size;
956 uint8_t *msg = _msg;
957 uint8_t digest[C_HASH_SIZE];
958
959 if (key == NULL || key->data == NULL || key->size == 0)
960 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
961
962 /* format:
963 * version - 2 bytes
964 * random - 32 bytes
965 * session_id - 1 byte length + content
966 * cookie - 1 byte length + content
967 */
968
969 pos = 34 + DTLS_RECORD_HEADER_SIZE + DTLS_HANDSHAKE_HEADER_SIZE;
970
971 if (msg_size < pos + 1)
972 return
973 gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
974
975 sid_size = msg[pos++];
976
977 if (sid_size > 32 || msg_size < pos + sid_size + 1)
978 return
979 gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
980
981 pos += sid_size;
982 cookie.size = msg[pos++];
983
984 if (msg_size < pos + cookie.size + 1)
985 return
986 gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
987
988 cookie.data = &msg[pos];
989 if (cookie.size != COOKIE_SIZE) {
990 if (cookie.size > 0)
991 _gnutls_audit_log(NULL,
992 "Received cookie with illegal size %d. Expected %d\n",
993 (int) cookie.size, COOKIE_SIZE);
994 return gnutls_assert_val(GNUTLS_E_BAD_COOKIE);
995 }
996
997 ret =
998 _gnutls_mac_fast(C_HASH, key->data, key->size, client_data,
999 client_data_size, digest);
1000 if (ret < 0)
1001 return gnutls_assert_val(ret);
1002
1003 if (memcmp(digest, cookie.data, COOKIE_MAC_SIZE) != 0)
1004 return gnutls_assert_val(GNUTLS_E_BAD_COOKIE);
1005
1006 prestate->record_seq = msg[10]; /* client's record seq */
1007 prestate->hsk_read_seq = msg[DTLS_RECORD_HEADER_SIZE + 5]; /* client's hsk seq */
1008 prestate->hsk_write_seq = 0; /* we always send zero for this msg */
1009
1010 return 0;
1011 }
1012
1013 /**
1014 * gnutls_dtls_prestate_set:
1015 * @session: a new session
1016 * @prestate: contains the client's prestate
1017 *
1018 * This function will associate the prestate acquired by
1019 * the cookie authentication with the client, with the newly
1020 * established session.
1021 *
1022 * This functions must be called after a successful gnutls_dtls_cookie_verify()
1023 * and should be succeeded by the actual DTLS handshake using gnutls_handshake().
1024 *
1025 * Since: 3.0
1026 **/
gnutls_dtls_prestate_set(gnutls_session_t session,gnutls_dtls_prestate_st * prestate)1027 void gnutls_dtls_prestate_set(gnutls_session_t session,
1028 gnutls_dtls_prestate_st * prestate)
1029 {
1030 record_parameters_st *params;
1031 int ret;
1032
1033 if (prestate == NULL)
1034 return;
1035
1036 /* we do not care about read_params, since we accept anything
1037 * the peer sends.
1038 */
1039 ret = _gnutls_epoch_get(session, EPOCH_WRITE_CURRENT, ¶ms);
1040 if (ret < 0)
1041 return;
1042
1043 params->write.sequence_number = prestate->record_seq;
1044
1045 session->internals.dtls.hsk_read_seq = prestate->hsk_read_seq;
1046 session->internals.dtls.hsk_write_seq =
1047 prestate->hsk_write_seq + 1;
1048 }
1049
1050 /**
1051 * gnutls_record_get_discarded:
1052 * @session: is a #gnutls_session_t type.
1053 *
1054 * Returns the number of discarded packets in a
1055 * DTLS connection.
1056 *
1057 * Returns: The number of discarded packets.
1058 *
1059 * Since: 3.0
1060 **/
gnutls_record_get_discarded(gnutls_session_t session)1061 unsigned int gnutls_record_get_discarded(gnutls_session_t session)
1062 {
1063 return session->internals.dtls.packets_dropped;
1064 }
1065