1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
/*
* OpenConnect (SSL + DTLS) VPN client
*
* Copyright © 2008-2015 Intel Corporation.
*
* Author: David Woodhouse <dwmw2@infradead.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include <config.h>
#include "openconnect-internal.h"
#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#define DTLS_EMPTY_BITMAP (0xFFFFFFFFFFFFFFFFULL)
/* Eventually we're going to have to have more than one incoming ESP
context at a time, to allow for the overlap period during a rekey.
So pass the 'esp' even though for now it's redundant. */
int verify_packet_seqno(struct openconnect_info *vpninfo,
struct esp *esp, uint32_t seq)
{
/*
* For incoming, esp->seq is the next *expected* packet, being
* the sequence number *after* the latest we have received.
*
* Since it must always be true that packet esp->seq-1 has been
* received, so there's no need to explicitly record that.
*
* So the backlog bitmap covers the 64 packets prior to that,
* with the LSB representing packet (esp->seq - 2), and the MSB
* representing (esp->seq - 65). A received packet is represented
* by a zero bit, and a missing packet is represented by a one.
*
* Thus we can allow out-of-order reception of packets that are
* within a reasonable interval of the latest packet received.
*/
if (seq == esp->seq) {
/* The common case. This is the packet we expected next. */
esp->seq_backlog <<= 1;
/* This might reach a value higher than the 32-bit ESP sequence
* numbers can actually reach. Which is fine. When that
* happens, we'll do the right thing and just not accept any
* newer packets. Someone needs to start a new epoch. */
esp->seq++;
vpn_progress(vpninfo, PRG_TRACE,
_("Accepting expected ESP packet with seq %u\n"),
seq);
return 0;
} else if (seq > esp->seq) {
/* The packet we were expecting has gone missing; this one is newer.
* We always advance the window to accommodate it. */
uint32_t delta = seq - esp->seq;
if (delta >= 64) {
/* We jumped a long way into the future. We have not seen
* any of the previous 32 packets so set the backlog bitmap
* to all ones. */
esp->seq_backlog = DTLS_EMPTY_BITMAP;
} else if (delta == 63) {
/* Avoid undefined behaviour that shifting by 64 would incur.
* The (clear) top bit represents the packet which is currently
* esp->seq - 1, which we know was already received. */
esp->seq_backlog = DTLS_EMPTY_BITMAP >> 1;
} else {
/* We have missed (delta) packets. Shift the backlog by that
* amount *plus* the one we would have shifted it anyway if
* we'd received the packet we were expecting. The zero bit
* representing the packet which is currently esp->seq - 1,
* which we know has been received, ends up at bit position
* (1<<delta). Then we set all the bits lower than that, which
* represent the missing packets. */
esp->seq_backlog <<= delta + 1;
esp->seq_backlog |= (1ULL << delta) - 1;
}
vpn_progress(vpninfo, PRG_TRACE,
_("Accepting later-than-expected ESP packet with seq %u (expected %" PRIu64 ")\n"),
seq, esp->seq);
esp->seq = (uint64_t)seq + 1;
return 0;
} else {
/* This packet is older than the one we were expecting. By how much...? */
uint32_t delta = esp->seq - seq;
/* delta==0 is the overflow case where esp->seq is 0x100000000 and seq is 0 */
if (delta > 65 || delta == 0) {
/* Too old. We can't know if it's a replay. */
if (vpninfo->esp_replay_protect) {
vpn_progress(vpninfo, PRG_DEBUG,
_("Discarding ancient ESP packet with seq %u (expected %" PRIu64 ")\n"),
seq, esp->seq);
return -EINVAL;
} else {
vpn_progress(vpninfo, PRG_DEBUG,
_("Tolerating ancient ESP packet with seq %u (expected %" PRIu64 ")\n"),
seq, esp->seq);
return 0;
}
} else if (delta == 1) {
/* Not in the bitmask since it is by definition already received. */
replayed:
if (vpninfo->esp_replay_protect) {
vpn_progress(vpninfo, PRG_DEBUG,
_("Discarding replayed ESP packet with seq %u\n"),
seq);
return -EINVAL;
} else {
vpn_progress(vpninfo, PRG_DEBUG,
_("Tolerating replayed ESP packet with seq %u\n"),
seq);
return 0;
}
} else {
/* Within the backlog window, so we remember whether we've seen it or not. */
uint64_t mask = 1ULL << (delta - 2);
if (!(esp->seq_backlog & mask))
goto replayed;
esp->seq_backlog &= ~mask;
vpn_progress(vpninfo, PRG_TRACE,
_("Accepting out-of-order ESP packet with seq %u (expected %" PRIu64 ")\n"),
seq, esp->seq);
return 0;
}
}
}
|