Coverage Report

Created: 2023-03-26 08:33

/src/gnutls/lib/dtls-sw.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2016 Red Hat, Inc.
3
 *
4
 * Authors: Fridolin Pokorny
5
 *    Nikos Mavrogiannopoulos
6
 *
7
 * This file is part of GNUTLS.
8
 *
9
 * The GNUTLS library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; either version 2.1 of
12
 * the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21
 *
22
 */
23
24
/* Functions that relate to DTLS sliding window handling.
25
 */
26
27
#ifndef DTLS_SW_NO_INCLUDES
28
# include "gnutls_int.h"
29
# include "errors.h"
30
# include "debug.h"
31
# include "dtls.h"
32
# include "record.h"
33
#endif
34
35
/*
36
 * DTLS sliding window handling
37
 */
38
0
#define DTLS_EPOCH_SHIFT    (6*CHAR_BIT)
39
0
#define DTLS_SEQ_NUM_MASK   0x0000FFFFFFFFFFFF
40
41
0
#define DTLS_EMPTY_BITMAP   (0xFFFFFFFFFFFFFFFFULL)
42
43
void _dtls_reset_window(struct record_parameters_st *rp)
44
0
{
45
0
  rp->dtls_sw_have_recv = 0;
46
0
}
47
48
/* Checks if a sequence number is not replayed. If a replayed
49
 * packet is detected it returns a negative value (but no sensible error code).
50
 * Otherwise zero.
51
 */
52
int _dtls_record_check(struct record_parameters_st *rp, uint64_t seq_num)
53
0
{
54
0
  if ((seq_num >> DTLS_EPOCH_SHIFT) != rp->epoch) {
55
0
    return gnutls_assert_val(-1);
56
0
  }
57
58
0
  seq_num &= DTLS_SEQ_NUM_MASK;
59
60
  /*
61
   * rp->dtls_sw_next is the next *expected* packet (N), being
62
   * the sequence number *after* the latest we have received.
63
   *
64
   * By definition, therefore, packet N-1 *has* been received.
65
   * And thus there's no point wasting a bit in the bitmap for it.
66
   *
67
   * So the backlog bitmap covers the 64 packets prior to that,
68
   * with the LSB representing packet (N - 2), and the MSB
69
   * representing (N - 65). A received packet is represented
70
   * by a zero bit, and a missing packet is represented by a one.
71
   *
72
   * Thus we can allow out-of-order reception of packets that are
73
   * within a reasonable interval of the latest packet received.
74
   */
75
0
  if (!rp->dtls_sw_have_recv) {
76
0
    rp->dtls_sw_next = seq_num + 1;
77
0
    rp->dtls_sw_bits = DTLS_EMPTY_BITMAP;
78
0
    rp->dtls_sw_have_recv = 1;
79
0
    return 0;
80
0
  } else if (seq_num == rp->dtls_sw_next) {
81
    /* The common case. This is the packet we expected next. */
82
83
0
    rp->dtls_sw_bits <<= 1;
84
85
    /* This might reach a value higher than 48-bit DTLS sequence
86
     * numbers can actually reach. Which is fine. When that
87
     * happens, we'll do the right thing and just not accept
88
     * any newer packets. Someone needs to start a new epoch. */
89
0
    rp->dtls_sw_next++;
90
0
    return 0;
91
0
  } else if (seq_num > rp->dtls_sw_next) {
92
    /* The packet we were expecting has gone missing; this one is newer.
93
     * We always advance the window to accommodate it. */
94
0
    uint64_t delta = seq_num - rp->dtls_sw_next;
95
96
0
    if (delta >= 64) {
97
      /* We jumped a long way into the future. We have not seen
98
       * any of the previous 32 packets so set the backlog bitmap
99
       * to all ones. */
100
0
      rp->dtls_sw_bits = DTLS_EMPTY_BITMAP;
101
0
    } else if (delta == 63) {
102
      /* Avoid undefined behaviour that shifting by 64 would incur.
103
       * The (clear) top bit represents the packet which is currently
104
       * rp->dtls_sw_next, which we know was already received. */
105
0
      rp->dtls_sw_bits = DTLS_EMPTY_BITMAP >> 1;
106
0
    } else {
107
      /* We have missed (delta) packets. Shift the backlog by that
108
       * amount *plus* the one we would have shifted it anyway if
109
       * we'd received the packet we were expecting. The zero bit
110
       * representing the packet which is currently rp->dtls_sw_next-1,
111
       * which we know has been received, ends up at bit position
112
       * (1<<delta). Then we set all the bits lower than that, which
113
       * represent the missing packets. */
114
0
      rp->dtls_sw_bits <<= delta + 1;
115
0
      rp->dtls_sw_bits |= (1ULL << delta) - 1;
116
0
    }
117
0
    rp->dtls_sw_next = seq_num + 1;
118
0
    return 0;
119
0
  } else {
120
    /* This packet is older than the one we were expecting. By how much...? */
121
0
    uint64_t delta = rp->dtls_sw_next - seq_num;
122
123
0
    if (delta > 65) {
124
      /* Too old. We can't know if it's a replay */
125
0
      return gnutls_assert_val(-2);
126
0
    } else if (delta == 1) {
127
      /* Not in the bitmask since it is by definition already received. */
128
0
      return gnutls_assert_val(-3);
129
0
    } else {
130
      /* Within the sliding window, so we remember whether we've seen it or not */
131
0
      uint64_t mask =
132
0
          1ULL << (rp->dtls_sw_next - seq_num - 2);
133
134
0
      if (!(rp->dtls_sw_bits & mask))
135
0
        return gnutls_assert_val(-3);
136
137
0
      rp->dtls_sw_bits &= ~mask;
138
0
      return 0;
139
0
    }
140
0
  }
141
0
}