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