Line data Source code
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 :
40 3173430 : void _dtls_async_timer_delete(gnutls_session_t session)
41 : {
42 3173430 : if (session->internals.dtls.async_term != 0) {
43 136 : _gnutls_dtls_log
44 : ("DTLS[%p]: Deinitializing previous handshake state.\n",
45 : session);
46 136 : session->internals.dtls.async_term = 0; /* turn off "timer" */
47 :
48 136 : _dtls_reset_hsk_state(session);
49 136 : _gnutls_handshake_io_buffer_clear(session);
50 136 : _gnutls_epoch_gc(session);
51 : }
52 3173430 : }
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
59 3813 : transmit_message(gnutls_session_t session,
60 : mbuffer_st * bufel, uint8_t ** buf)
61 : {
62 3813 : uint8_t *data, *mtu_data;
63 3813 : int ret = 0;
64 3813 : unsigned int offset, frag_len, data_size;
65 3813 : unsigned int mtu =
66 3813 : gnutls_dtls_get_data_mtu(session);
67 :
68 3813 : if (session->security_parameters.max_record_send_size < mtu)
69 9 : mtu = session->security_parameters.max_record_send_size;
70 :
71 3813 : mtu -= DTLS_HANDSHAKE_HEADER_SIZE;
72 :
73 3813 : if (bufel->type == GNUTLS_CHANGE_CIPHER_SPEC) {
74 791 : _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 791 : return _gnutls_send_int(session, bufel->type, -1,
80 791 : bufel->epoch,
81 791 : _mbuffer_get_uhead_ptr(bufel),
82 : _mbuffer_get_uhead_size(bufel), 0);
83 : }
84 :
85 3022 : if (*buf == NULL)
86 1403 : *buf = gnutls_malloc(mtu + DTLS_HANDSHAKE_HEADER_SIZE);
87 3022 : if (*buf == NULL)
88 0 : return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
89 :
90 3022 : mtu_data = *buf;
91 :
92 3022 : data = _mbuffer_get_udata_ptr(bufel);
93 3022 : data_size = _mbuffer_get_udata_size(bufel);
94 :
95 : /* Write fixed headers
96 : */
97 :
98 : /* Handshake type */
99 3022 : mtu_data[0] = (uint8_t) bufel->htype;
100 :
101 : /* Total length */
102 3022 : _gnutls_write_uint24(data_size, &mtu_data[1]);
103 :
104 : /* Handshake sequence */
105 3022 : _gnutls_write_uint16(bufel->handshake_sequence, &mtu_data[4]);
106 :
107 : /* Chop up and send handshake message into mtu-size pieces. */
108 6238 : for (offset = 0; offset <= data_size; offset += mtu) {
109 : /* Calculate fragment length */
110 3217 : if (offset + mtu > data_size)
111 3022 : 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 3217 : if (frag_len == 0 && data_size > 0) {
119 : ret = 0;
120 : break;
121 : }
122 :
123 : /* Fragment offset */
124 3216 : _gnutls_write_uint24(offset, &mtu_data[6]);
125 :
126 : /* Fragment length */
127 3216 : _gnutls_write_uint24(frag_len, &mtu_data[9]);
128 :
129 3216 : memcpy(&mtu_data[DTLS_HANDSHAKE_HEADER_SIZE],
130 3216 : data + offset, frag_len);
131 :
132 3216 : _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 6432 : ret = _gnutls_send_int(session, bufel->type, bufel->htype,
140 3216 : bufel->epoch, mtu_data,
141 3216 : DTLS_HANDSHAKE_HEADER_SIZE +
142 : frag_len, 0);
143 3216 : if (ret < 0) {
144 0 : gnutls_assert();
145 : break;
146 : }
147 : }
148 :
149 : return ret;
150 : }
151 :
152 1032 : static int drop_usage_count(gnutls_session_t session,
153 : mbuffer_head_st * const send_buffer)
154 : {
155 1032 : int ret;
156 1032 : mbuffer_st *cur;
157 :
158 3663 : for (cur = send_buffer->head; cur != NULL; cur = cur->next) {
159 2631 : ret = _gnutls_epoch_refcount_dec(session, cur->epoch);
160 2631 : if (ret < 0)
161 0 : 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 : */
175 566309 : static int is_next_hpacket_expected(gnutls_session_t session)
176 : {
177 566309 : int ret;
178 :
179 : /* htype is arbitrary */
180 1132620 : ret =
181 566309 : _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE,
182 : GNUTLS_HANDSHAKE_FINISHED, 0);
183 566309 : if (ret < 0)
184 565689 : return gnutls_assert_val(ret);
185 :
186 620 : ret = _gnutls_parse_record_buffered_msgs(session);
187 620 : if (ret < 0)
188 0 : return gnutls_assert_val(ret);
189 :
190 620 : if (session->internals.handshake_recv_buffer_size > 0)
191 : return 0;
192 : else
193 22 : return
194 22 : gnutls_assert_val
195 : (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
196 : }
197 :
198 1032 : void _dtls_reset_hsk_state(gnutls_session_t session)
199 : {
200 1032 : session->internals.dtls.flight_init = 0;
201 1032 : drop_usage_count(session,
202 : &session->internals.handshake_send_buffer);
203 1032 : _mbuffer_head_clear(&session->internals.handshake_send_buffer);
204 1032 : }
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 : */
223 7546340 : int _dtls_transmit(gnutls_session_t session)
224 : {
225 7546340 : int ret;
226 7546340 : uint8_t *buf = NULL;
227 7546340 : unsigned int timeout;
228 :
229 : /* PREPARING -> SENDING state transition */
230 7546340 : mbuffer_head_st *const send_buffer =
231 : &session->internals.handshake_send_buffer;
232 7546340 : mbuffer_st *cur;
233 7546340 : gnutls_handshake_description_t last_type = 0;
234 7546340 : unsigned int diff;
235 7546340 : struct timespec now;
236 :
237 7546340 : 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 7546340 : if (session->internals.dtls.flight_init != 0
244 7545140 : && (session->internals.flags & GNUTLS_NONBLOCK)) {
245 : /* just in case previous run was interrupted */
246 7544910 : ret = _gnutls_io_write_flush(session);
247 7544910 : if (ret < 0) {
248 2 : gnutls_assert();
249 2 : goto cleanup;
250 : }
251 :
252 7544900 : if (session->internals.dtls.last_flight == 0
253 7546460 : || !_dtls_is_async(session)) {
254 : /* check for ACK */
255 7544900 : ret = _gnutls_io_check_recv(session, 0);
256 7544900 : if (ret == GNUTLS_E_TIMEDOUT) {
257 : /* if no retransmission is required yet just return
258 : */
259 6978980 : if (timespec_sub_ms
260 : (&now,
261 : &session->internals.dtls.
262 6978980 : last_retransmit) < TIMER_WINDOW) {
263 6978980 : gnutls_assert();
264 6978980 : goto nb_timeout;
265 : }
266 : } else { /* received something */
267 :
268 565920 : if (ret == 0) {
269 565920 : ret =
270 565920 : is_next_hpacket_expected
271 : (session);
272 565920 : if (ret == GNUTLS_E_AGAIN
273 565920 : || ret == GNUTLS_E_INTERRUPTED)
274 565665 : goto nb_timeout;
275 255 : if (ret < 0
276 255 : && ret !=
277 : GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET)
278 : {
279 0 : gnutls_assert();
280 0 : goto cleanup;
281 : }
282 255 : if (ret == 0)
283 255 : goto end_flight;
284 : /* if ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET retransmit */
285 : } else
286 0 : goto nb_timeout;
287 : }
288 : }
289 : }
290 :
291 1559 : do {
292 1559 : timeout = TIMER_WINDOW;
293 :
294 1559 : diff =
295 1559 : timespec_sub_ms(&now,
296 : &session->internals.handshake_start_time);
297 1559 : if (diff >= session->internals.handshake_timeout_ms) {
298 1 : _gnutls_dtls_log("Session timeout: %u ms\n", diff);
299 1 : ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
300 1 : goto end_flight;
301 : }
302 :
303 1558 : diff =
304 1558 : timespec_sub_ms(&now,
305 : &session->internals.dtls.
306 : last_retransmit);
307 1558 : if (session->internals.dtls.flight_init == 0
308 358 : || diff >= TIMER_WINDOW) {
309 1472 : _gnutls_dtls_log
310 : ("DTLS[%p]: %sStart of flight transmission.\n",
311 : session,
312 : (session->internals.dtls.flight_init ==
313 : 0) ? "" : "re-");
314 5285 : for (cur = send_buffer->head; cur != NULL;
315 3813 : cur = cur->next) {
316 3813 : ret = transmit_message(session, cur, &buf);
317 3813 : if (ret < 0) {
318 0 : gnutls_assert();
319 0 : goto end_flight;
320 : }
321 :
322 3813 : last_type = cur->htype;
323 : }
324 1472 : gnutls_gettime(&session->internals.dtls.last_retransmit);
325 :
326 1472 : if (session->internals.dtls.flight_init == 0) {
327 1200 : session->internals.dtls.flight_init = 1;
328 1200 : RESET_TIMER;
329 1200 : timeout = TIMER_WINDOW;
330 :
331 1200 : 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 599 : session->internals.dtls.
337 599 : last_flight = 1;
338 : } else
339 601 : session->internals.dtls.
340 601 : last_flight = 0;
341 : } else {
342 272 : UPDATE_TIMER;
343 : }
344 : }
345 :
346 1558 : ret = _gnutls_io_write_flush(session);
347 1558 : if (ret < 0) {
348 2 : ret = gnutls_assert_val(ret);
349 2 : goto cleanup;
350 : }
351 :
352 : /* last message in handshake -> no ack */
353 1556 : 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 814 : ret = 0;
360 814 : goto cleanup;
361 : } else { /* all other messages -> implicit ack (receive of next flight) */
362 :
363 742 : if (!(session->internals.flags & GNUTLS_NONBLOCK))
364 485 : ret =
365 485 : _gnutls_io_check_recv(session,
366 : timeout);
367 : else {
368 257 : ret = _gnutls_io_check_recv(session, 0);
369 257 : if (ret == GNUTLS_E_TIMEDOUT) {
370 248 : goto nb_timeout;
371 : }
372 : }
373 :
374 494 : if (ret == 0) {
375 389 : ret = is_next_hpacket_expected(session);
376 389 : if (ret == GNUTLS_E_AGAIN
377 389 : || ret == GNUTLS_E_INTERRUPTED)
378 24 : goto nb_timeout;
379 :
380 365 : if (ret ==
381 : GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET) {
382 22 : ret = GNUTLS_E_TIMEDOUT;
383 22 : goto keep_up;
384 : }
385 343 : if (ret < 0) {
386 0 : gnutls_assert();
387 0 : goto cleanup;
388 : }
389 343 : goto end_flight;
390 : }
391 : }
392 :
393 105 : keep_up:
394 127 : gnutls_gettime(&now);
395 127 : } while (ret == GNUTLS_E_TIMEDOUT);
396 :
397 0 : if (ret < 0) {
398 0 : ret = gnutls_assert_val(ret);
399 0 : goto end_flight;
400 : }
401 :
402 : ret = 0;
403 :
404 599 : end_flight:
405 599 : _gnutls_dtls_log("DTLS[%p]: End of flight transmission.\n",
406 : session);
407 599 : _dtls_reset_hsk_state(session);
408 :
409 1417 : cleanup:
410 1417 : if (buf != NULL)
411 1133 : gnutls_free(buf);
412 :
413 : /* SENDING -> WAITING state transition */
414 : return ret;
415 :
416 7544920 : nb_timeout:
417 7544920 : if (buf != NULL)
418 270 : gnutls_free(buf);
419 :
420 7544930 : 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 : */
426 518366 : int _dtls_wait_and_retransmit(gnutls_session_t session)
427 : {
428 518366 : int ret;
429 :
430 518366 : if (!(session->internals.flags & GNUTLS_NONBLOCK))
431 721 : ret = _gnutls_io_check_recv(session, TIMER_WINDOW);
432 : else
433 517645 : ret = _gnutls_io_check_recv(session, 0);
434 :
435 518366 : if (ret == GNUTLS_E_TIMEDOUT) {
436 247 : ret = _dtls_retransmit(session);
437 247 : if (ret == 0) {
438 280 : RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, 0);
439 : } else
440 107 : return gnutls_assert_val(ret);
441 : }
442 :
443 518119 : RESET_TIMER;
444 518119 : 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 : **/
466 1316 : void gnutls_dtls_set_timeouts(gnutls_session_t session,
467 : unsigned int retrans_timeout,
468 : unsigned int total_timeout)
469 : {
470 1316 : if (total_timeout == GNUTLS_INDEFINITE_TIMEOUT)
471 0 : session->internals.handshake_timeout_ms = 0;
472 : else
473 1316 : session->internals.handshake_timeout_ms = total_timeout;
474 :
475 1316 : session->internals.dtls.retrans_timeout_ms = retrans_timeout;
476 1316 : }
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 : **/
491 426 : void gnutls_dtls_set_mtu(gnutls_session_t session, unsigned int mtu)
492 : {
493 426 : session->internals.dtls.mtu = MIN(mtu, DEFAULT_MAX_RECORD_SIZE);
494 426 : }
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 */
499 438820 : 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 438820 : int total = 0;
505 438820 : int ret;
506 438820 : int hash_len = 0;
507 :
508 438820 : if (unlikely(cipher == NULL))
509 : return 0;
510 :
511 : /* 1 octet content type in the unencrypted content */
512 438820 : if (ver->tls13_sem)
513 420101 : total++;
514 :
515 438820 : if (mac->id == GNUTLS_MAC_AEAD) {
516 434185 : if (!ver->tls13_sem)
517 14084 : total += _gnutls_cipher_get_explicit_iv_size(cipher);
518 :
519 434185 : total += _gnutls_cipher_get_tag_size(cipher);
520 : } else {
521 : /* STREAM + BLOCK have a MAC appended */
522 4635 : ret = _gnutls_mac_get_algo_len(mac);
523 4635 : if (unlikely(ret < 0))
524 : return 0;
525 :
526 4635 : hash_len = ret;
527 4635 : total += hash_len;
528 : }
529 :
530 : /* Block ciphers have padding + IV */
531 438820 : if (_gnutls_cipher_type(cipher) == CIPHER_BLOCK) {
532 4441 : int exp_iv;
533 :
534 4441 : exp_iv = _gnutls_cipher_get_explicit_iv_size(cipher);
535 :
536 4441 : if (max)
537 4440 : total += 2*exp_iv; /* block == iv size */
538 : else
539 1 : total += exp_iv + 1;
540 : }
541 :
542 438820 : 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 : **/
563 0 : 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 0 : const cipher_entry_st *c;
570 0 : const mac_entry_st *m;
571 0 : const version_entry_st *v;
572 0 : size_t total = 0;
573 :
574 0 : c = cipher_to_entry(cipher);
575 0 : if (c == NULL)
576 : return 0;
577 :
578 0 : m = mac_to_entry(mac);
579 0 : if (m == NULL)
580 : return 0;
581 :
582 0 : v = version_to_entry(version);
583 0 : if (v == NULL)
584 : return 0;
585 :
586 0 : if (v->transport == GNUTLS_STREAM)
587 : total = TLS_RECORD_HEADER_SIZE;
588 : else
589 0 : total = DTLS_RECORD_HEADER_SIZE;
590 :
591 0 : total += _gnutls_record_overhead(v, c, m, 1);
592 :
593 0 : 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 : */
605 420288 : static int record_overhead_rt(gnutls_session_t session)
606 : {
607 420288 : record_parameters_st *params;
608 420288 : int ret;
609 :
610 420288 : if (session->internals.initial_negotiation_completed == 0)
611 : return GNUTLS_E_INVALID_REQUEST;
612 420152 : ret = _gnutls_epoch_get(session, EPOCH_WRITE_CURRENT, ¶ms);
613 420152 : if (ret < 0)
614 0 : return gnutls_assert_val(ret);
615 :
616 420152 : 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 : **/
630 420235 : size_t gnutls_record_overhead_size(gnutls_session_t session)
631 : {
632 420235 : const version_entry_st *v = get_version(session);
633 420235 : int ret;
634 420235 : size_t total;
635 :
636 420235 : if (v->transport == GNUTLS_STREAM)
637 : total = TLS_RECORD_HEADER_SIZE;
638 : else
639 0 : total = DTLS_RECORD_HEADER_SIZE;
640 :
641 420235 : ret = record_overhead_rt(session);
642 420235 : if (ret >= 0)
643 420099 : total += ret;
644 :
645 420235 : 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 : **/
662 24195 : unsigned int gnutls_dtls_get_data_mtu(gnutls_session_t session)
663 : {
664 24195 : int mtu = session->internals.dtls.mtu;
665 24195 : record_parameters_st *params;
666 24195 : int ret, k, hash_size, block;
667 :
668 24195 : mtu -= RECORD_HEADER_SIZE(session);
669 :
670 24195 : if (session->internals.initial_negotiation_completed == 0)
671 11485 : return mtu;
672 :
673 12710 : ret = _gnutls_epoch_get(session, EPOCH_WRITE_CURRENT, ¶ms);
674 12710 : if (ret < 0)
675 0 : return mtu;
676 :
677 12710 : if (params->cipher->type == CIPHER_AEAD || params->cipher->type == CIPHER_STREAM)
678 9239 : 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 3471 : hash_size = _gnutls_mac_get_algo_len(params->mac);
683 3471 : block = _gnutls_cipher_get_explicit_iv_size(params->cipher);
684 6942 : assert(_gnutls_cipher_get_block_size(params->cipher) == block);
685 :
686 3471 : 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 1342 : k = ((mtu-hash_size)/block) - 2;
697 :
698 1342 : 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 2129 : k = ((mtu)/block) - 2;
710 :
711 2129 : 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 : **/
735 53 : int gnutls_dtls_set_data_mtu(gnutls_session_t session, unsigned int mtu)
736 : {
737 53 : int overhead;
738 :
739 53 : overhead = record_overhead_rt(session);
740 :
741 : /* You can't call this until the session is actually running */
742 53 : if (overhead < 0)
743 : return GNUTLS_E_INVALID_SESSION;
744 :
745 : /* Add the overhead inside the encrypted part */
746 53 : mtu += overhead;
747 :
748 : /* Add the *unencrypted header size */
749 53 : mtu += RECORD_HEADER_SIZE(session);
750 :
751 53 : gnutls_dtls_set_mtu(session, mtu);
752 53 : 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 : **/
768 20208 : unsigned int gnutls_dtls_get_mtu(gnutls_session_t session)
769 : {
770 20208 : 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 : **/
787 380 : unsigned int gnutls_dtls_get_timeout(gnutls_session_t session)
788 : {
789 380 : struct timespec now;
790 380 : unsigned int diff;
791 :
792 380 : gnutls_gettime(&now);
793 :
794 380 : diff =
795 380 : timespec_sub_ms(&now,
796 : &session->internals.dtls.last_retransmit);
797 380 : if (diff >= TIMER_WINDOW)
798 : return 0;
799 : else
800 211 : 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 : **/
839 49 : 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 49 : uint8_t hvr[20 + DTLS_HANDSHAKE_HEADER_SIZE + COOKIE_SIZE];
846 49 : int hvr_size = 0, ret;
847 49 : uint8_t digest[C_HASH_SIZE];
848 :
849 49 : if (key == NULL || key->data == NULL || key->size == 0)
850 0 : 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 49 : hvr[hvr_size++] = GNUTLS_HANDSHAKE;
878 : /* version */
879 49 : hvr[hvr_size++] = 254;
880 49 : hvr[hvr_size++] = 255;
881 :
882 : /* epoch + seq */
883 49 : memset(&hvr[hvr_size], 0, 8);
884 49 : hvr_size += 7;
885 49 : hvr[hvr_size++] = prestate->record_seq;
886 :
887 : /* length */
888 49 : _gnutls_write_uint16(DTLS_HANDSHAKE_HEADER_SIZE + COOKIE_SIZE + 3,
889 : &hvr[hvr_size]);
890 49 : hvr_size += 2;
891 :
892 : /* now handshake headers */
893 49 : hvr[hvr_size++] = GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST;
894 49 : _gnutls_write_uint24(COOKIE_SIZE + 3, &hvr[hvr_size]);
895 49 : hvr_size += 3;
896 :
897 : /* handshake seq */
898 49 : hvr[hvr_size++] = 0;
899 49 : hvr[hvr_size++] = prestate->hsk_write_seq;
900 :
901 49 : _gnutls_write_uint24(0, &hvr[hvr_size]);
902 49 : hvr_size += 3;
903 :
904 49 : _gnutls_write_uint24(COOKIE_SIZE + 3, &hvr[hvr_size]);
905 49 : hvr_size += 3;
906 :
907 : /* version */
908 49 : hvr[hvr_size++] = 254;
909 49 : hvr[hvr_size++] = 255;
910 49 : hvr[hvr_size++] = COOKIE_SIZE;
911 :
912 49 : ret =
913 49 : _gnutls_mac_fast(C_HASH, key->data, key->size, client_data,
914 : client_data_size, digest);
915 49 : if (ret < 0)
916 0 : return gnutls_assert_val(ret);
917 :
918 49 : memcpy(&hvr[hvr_size], digest, COOKIE_MAC_SIZE);
919 49 : hvr_size += COOKIE_MAC_SIZE;
920 :
921 49 : ret = push_func(ptr, hvr, hvr_size);
922 49 : if (ret < 0)
923 0 : 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 : **/
948 97 : 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 97 : gnutls_datum_t cookie;
954 97 : int ret;
955 97 : unsigned int pos, sid_size;
956 97 : uint8_t *msg = _msg;
957 97 : uint8_t digest[C_HASH_SIZE];
958 :
959 97 : if (key == NULL || key->data == NULL || key->size == 0)
960 0 : 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 97 : pos = 34 + DTLS_RECORD_HEADER_SIZE + DTLS_HANDSHAKE_HEADER_SIZE;
970 :
971 97 : if (msg_size < pos + 1)
972 0 : return
973 0 : gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
974 :
975 97 : sid_size = msg[pos++];
976 :
977 97 : if (sid_size > 32 || msg_size < pos + sid_size + 1)
978 0 : return
979 0 : gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
980 :
981 97 : pos += sid_size;
982 97 : cookie.size = msg[pos++];
983 :
984 97 : if (msg_size < pos + cookie.size + 1)
985 0 : return
986 0 : gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
987 :
988 97 : cookie.data = &msg[pos];
989 97 : if (cookie.size != COOKIE_SIZE) {
990 49 : if (cookie.size > 0)
991 0 : _gnutls_audit_log(NULL,
992 : "Received cookie with illegal size %d. Expected %d\n",
993 : (int) cookie.size, COOKIE_SIZE);
994 49 : return gnutls_assert_val(GNUTLS_E_BAD_COOKIE);
995 : }
996 :
997 48 : ret =
998 48 : _gnutls_mac_fast(C_HASH, key->data, key->size, client_data,
999 : client_data_size, digest);
1000 48 : if (ret < 0)
1001 0 : return gnutls_assert_val(ret);
1002 :
1003 48 : if (memcmp(digest, cookie.data, COOKIE_MAC_SIZE) != 0)
1004 0 : return gnutls_assert_val(GNUTLS_E_BAD_COOKIE);
1005 :
1006 48 : prestate->record_seq = msg[10]; /* client's record seq */
1007 48 : prestate->hsk_read_seq = msg[DTLS_RECORD_HEADER_SIZE + 5]; /* client's hsk seq */
1008 48 : prestate->hsk_write_seq = 0; /* we always send zero for this msg */
1009 :
1010 48 : 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 : **/
1027 48 : void gnutls_dtls_prestate_set(gnutls_session_t session,
1028 : gnutls_dtls_prestate_st * prestate)
1029 : {
1030 48 : record_parameters_st *params;
1031 48 : int ret;
1032 :
1033 48 : if (prestate == NULL)
1034 0 : return;
1035 :
1036 : /* we do not care about read_params, since we accept anything
1037 : * the peer sends.
1038 : */
1039 48 : ret = _gnutls_epoch_get(session, EPOCH_WRITE_CURRENT, ¶ms);
1040 48 : if (ret < 0)
1041 : return;
1042 :
1043 48 : params->write.sequence_number = prestate->record_seq;
1044 :
1045 48 : session->internals.dtls.hsk_read_seq = prestate->hsk_read_seq;
1046 48 : session->internals.dtls.hsk_write_seq =
1047 48 : 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 : **/
1061 0 : unsigned int gnutls_record_get_discarded(gnutls_session_t session)
1062 : {
1063 0 : return session->internals.dtls.packets_dropped;
1064 : }
|