Coverage Report

Created: 2023-03-26 08:33

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