Coverage Report

Created: 2025-03-18 06:55

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