123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- /*
- * 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;
- }
- }
- }
|