|
Packit |
549fdc |
/*
|
|
Packit |
549fdc |
* Copyright (C) 2016 Red Hat, Inc.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Authors: Fridolin Pokorny
|
|
Packit |
549fdc |
* Nikos Mavrogiannopoulos
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This file is part of GNUTLS.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The GNUTLS library is free software; you can redistribute it and/or
|
|
Packit |
549fdc |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit |
549fdc |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
549fdc |
* the License, or (at your option) any later version.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This library is distributed in the hope that it will be useful, but
|
|
Packit |
549fdc |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
549fdc |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
549fdc |
* Lesser General Public License for more details.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
549fdc |
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Functions that relate to DTLS sliding window handling.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
#ifndef DTLS_SW_NO_INCLUDES
|
|
Packit |
549fdc |
#include "gnutls_int.h"
|
|
Packit |
549fdc |
#include "errors.h"
|
|
Packit |
549fdc |
#include "debug.h"
|
|
Packit |
549fdc |
#include "dtls.h"
|
|
Packit |
549fdc |
#include "record.h"
|
|
Packit |
549fdc |
#endif
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/*
|
|
Packit |
549fdc |
* DTLS sliding window handling
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
#define DTLS_EPOCH_SHIFT (6*CHAR_BIT)
|
|
Packit |
549fdc |
#define DTLS_SEQ_NUM_MASK 0x0000FFFFFFFFFFFF
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
#define DTLS_EMPTY_BITMAP (0xFFFFFFFFFFFFFFFFULL)
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* We expect the compiler to be able to spot that this is a byteswapping
|
|
Packit |
549fdc |
* load, and emit instructions like 'movbe' on x86_64 where appropriate.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
#define LOAD_UINT64(out, ubytes) \
|
|
Packit |
549fdc |
out = (((uint64_t)ubytes[0] << 56) | \
|
|
Packit |
549fdc |
((uint64_t)ubytes[1] << 48) | \
|
|
Packit |
549fdc |
((uint64_t)ubytes[2] << 40) | \
|
|
Packit |
549fdc |
((uint64_t)ubytes[3] << 32) | \
|
|
Packit |
549fdc |
((uint64_t)ubytes[4] << 24) | \
|
|
Packit |
549fdc |
((uint64_t)ubytes[5] << 16) | \
|
|
Packit |
549fdc |
((uint64_t)ubytes[6] << 8) | \
|
|
Packit |
549fdc |
((uint64_t)ubytes[7] << 0) )
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
void _dtls_reset_window(struct record_parameters_st *rp)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
rp->dtls_sw_have_recv = 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Checks if a sequence number is not replayed. If a replayed
|
|
Packit |
549fdc |
* packet is detected it returns a negative value (but no sensible error code).
|
|
Packit |
549fdc |
* Otherwise zero.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
int _dtls_record_check(struct record_parameters_st *rp, gnutls_uint64 * _seq)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
uint64_t seq_num = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
LOAD_UINT64(seq_num, _seq->i);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if ((seq_num >> DTLS_EPOCH_SHIFT) != rp->epoch) {
|
|
Packit |
549fdc |
return gnutls_assert_val(-1);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
seq_num &= DTLS_SEQ_NUM_MASK;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/*
|
|
Packit |
549fdc |
* rp->dtls_sw_next is the next *expected* packet (N), being
|
|
Packit |
549fdc |
* the sequence number *after* the latest we have received.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* By definition, therefore, packet N-1 *has* been received.
|
|
Packit |
549fdc |
* And thus there's no point wasting a bit in the bitmap for it.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* So the backlog bitmap covers the 64 packets prior to that,
|
|
Packit |
549fdc |
* with the LSB representing packet (N - 2), and the MSB
|
|
Packit |
549fdc |
* representing (N - 65). A received packet is represented
|
|
Packit |
549fdc |
* by a zero bit, and a missing packet is represented by a one.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Thus we can allow out-of-order reception of packets that are
|
|
Packit |
549fdc |
* within a reasonable interval of the latest packet received.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
if (!rp->dtls_sw_have_recv) {
|
|
Packit |
549fdc |
rp->dtls_sw_next = seq_num + 1;
|
|
Packit |
549fdc |
rp->dtls_sw_bits = DTLS_EMPTY_BITMAP;
|
|
Packit |
549fdc |
rp->dtls_sw_have_recv = 1;
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
} else if (seq_num == rp->dtls_sw_next) {
|
|
Packit |
549fdc |
/* The common case. This is the packet we expected next. */
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
rp->dtls_sw_bits <<= 1;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* This might reach a value higher than 48-bit DTLS sequence
|
|
Packit |
549fdc |
* numbers can actually reach. Which is fine. When that
|
|
Packit |
549fdc |
* happens, we'll do the right thing and just not accept
|
|
Packit |
549fdc |
* any newer packets. Someone needs to start a new epoch. */
|
|
Packit |
549fdc |
rp->dtls_sw_next++;
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
} else if (seq_num > rp->dtls_sw_next) {
|
|
Packit |
549fdc |
/* The packet we were expecting has gone missing; this one is newer.
|
|
Packit |
549fdc |
* We always advance the window to accommodate it. */
|
|
Packit |
549fdc |
uint64_t delta = seq_num - rp->dtls_sw_next;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (delta >= 64) {
|
|
Packit |
549fdc |
/* We jumped a long way into the future. We have not seen
|
|
Packit |
549fdc |
* any of the previous 32 packets so set the backlog bitmap
|
|
Packit |
549fdc |
* to all ones. */
|
|
Packit |
549fdc |
rp->dtls_sw_bits = DTLS_EMPTY_BITMAP;
|
|
Packit |
549fdc |
} else if (delta == 63) {
|
|
Packit |
549fdc |
/* Avoid undefined behaviour that shifting by 64 would incur.
|
|
Packit |
549fdc |
* The (clear) top bit represents the packet which is currently
|
|
Packit |
549fdc |
* rp->dtls_sw_next, which we know was already received. */
|
|
Packit |
549fdc |
rp->dtls_sw_bits = DTLS_EMPTY_BITMAP >> 1;
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
/* We have missed (delta) packets. Shift the backlog by that
|
|
Packit |
549fdc |
* amount *plus* the one we would have shifted it anyway if
|
|
Packit |
549fdc |
* we'd received the packet we were expecting. The zero bit
|
|
Packit |
549fdc |
* representing the packet which is currently rp->dtls_sw_next-1,
|
|
Packit |
549fdc |
* which we know has been received, ends up at bit position
|
|
Packit |
549fdc |
* (1<
|
|
Packit |
549fdc |
* represent the missing packets. */
|
|
Packit |
549fdc |
rp->dtls_sw_bits <<= delta + 1;
|
|
Packit |
549fdc |
rp->dtls_sw_bits |= (1ULL << delta) - 1;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
rp->dtls_sw_next = seq_num + 1;
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
/* This packet is older than the one we were expecting. By how much...? */
|
|
Packit |
549fdc |
uint64_t delta = rp->dtls_sw_next - seq_num;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (delta > 65) {
|
|
Packit |
549fdc |
/* Too old. We can't know if it's a replay */
|
|
Packit |
549fdc |
return gnutls_assert_val(-2);
|
|
Packit |
549fdc |
} else if (delta == 1) {
|
|
Packit |
549fdc |
/* Not in the bitmask since it is by definition already received. */
|
|
Packit |
549fdc |
return gnutls_assert_val(-3);
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
/* Within the sliding window, so we remember whether we've seen it or not */
|
|
Packit |
549fdc |
uint64_t mask = 1ULL << (rp->dtls_sw_next - seq_num - 2);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (!(rp->dtls_sw_bits & mask))
|
|
Packit |
549fdc |
return gnutls_assert_val(-3);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
rp->dtls_sw_bits &= ~mask;
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|