~lopin/openconnect/lopin-gp-deb-2

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
/*
 * 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 <stdint.h>
#include <inttypes.h>
#include <stdlib.h>
#include <errno.h>

#include "openconnect-internal.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. */
			vpn_progress(vpninfo, PRG_DEBUG,
				     _("Discarding ancient ESP packet with seq %u (expected %" PRIu64 ")\n"),
				     seq, esp->seq);
			return -EINVAL;
		} else if (delta == 1) {
			/* Not in the bitmask since it is by definition already received. */
		replayed:
			vpn_progress(vpninfo, PRG_DEBUG,
				     _("Discarding replayed ESP packet with seq %u\n"),
				     seq);
			return -EINVAL;
		} 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;
		}
	}
}