Botan 3.13.0
Crypto and TLS for C&
tls_seq_numbers.h
Go to the documentation of this file.
1/*
2* TLS Sequence Number Handling
3* (C) 2012 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#ifndef BOTAN_TLS_SEQ_NUMBERS_H_
9#define BOTAN_TLS_SEQ_NUMBERS_H_
10
11#include <botan/assert.h>
12#include <botan/exceptn.h>
13#include <limits>
14#include <map>
15
16namespace Botan::TLS {
17
18class Connection_Sequence_Numbers /* NOLINT(*-special-member-functions) */ {
19 public:
20 virtual ~Connection_Sequence_Numbers() = default;
21
22 virtual void new_read_cipher_state() = 0;
23 virtual void new_write_cipher_state() = 0;
24
25 virtual uint16_t current_read_epoch() const = 0;
26 virtual uint16_t current_write_epoch() const = 0;
27
28 virtual uint64_t next_write_sequence(uint16_t) = 0;
29 virtual uint64_t next_read_sequence() = 0;
30
31 virtual bool already_seen(uint64_t seq) const = 0;
32 virtual void read_accept(uint64_t seq) = 0;
33
34 virtual void reset() = 0;
35};
36
38 public:
39 Stream_Sequence_Numbers() : m_write_seq_no(0), m_read_seq_no(0), m_read_epoch(0), m_write_epoch(0) {}
40
41 void reset() override {
42 m_write_seq_no = 0;
43 m_read_seq_no = 0;
44 m_read_epoch = 0;
45 m_write_epoch = 0;
46 }
47
48 void new_read_cipher_state() override {
49 m_read_seq_no = 0;
50 m_read_epoch++;
51 }
52
53 void new_write_cipher_state() override {
54 m_write_seq_no = 0;
55 m_write_epoch++;
56 }
57
58 uint16_t current_read_epoch() const override { return m_read_epoch; }
59
60 uint16_t current_write_epoch() const override { return m_write_epoch; }
61
62 uint64_t next_write_sequence(uint16_t /*epoch*/) override {
63 if(m_write_seq_no == std::numeric_limits<uint64_t>::max()) {
64 throw Invalid_State("TLS 1.2 write sequence number overflow");
65 }
66 return m_write_seq_no++;
67 }
68
69 uint64_t next_read_sequence() override { return m_read_seq_no; }
70
71 bool already_seen(uint64_t /*seq*/) const override { return false; }
72
73 void read_accept(uint64_t /*seq*/) override {
74 if(m_read_seq_no == std::numeric_limits<uint64_t>::max()) {
75 throw Invalid_State("TLS 1.2 read sequence number overflow");
76 }
77 m_read_seq_no++;
78 }
79
80 private:
81 uint64_t m_write_seq_no;
82 uint64_t m_read_seq_no;
83 uint16_t m_read_epoch;
84 uint16_t m_write_epoch;
85};
86
88 public:
90
91 void reset() override {
92 m_write_seqs.clear();
93 m_write_seqs[0] = 0;
94 m_write_epoch = 0;
95 m_read_epoch = 0;
96 m_read_windows.clear();
97 m_read_windows[0] = Replay_Window{};
98 }
99
100 void new_read_cipher_state() override {
101 m_read_epoch = next_epoch(m_read_epoch);
102 m_read_windows.try_emplace(m_read_epoch);
103 prune_epochs(m_read_windows, m_read_epoch);
104 }
105
106 void new_write_cipher_state() override {
107 m_write_epoch = next_epoch(m_write_epoch);
108 m_write_seqs[m_write_epoch] = 0;
109 prune_epochs(m_write_seqs, m_write_epoch);
110 }
111
112 uint16_t current_read_epoch() const override { return m_read_epoch; }
113
114 uint16_t current_write_epoch() const override { return m_write_epoch; }
115
116 uint64_t next_write_sequence(uint16_t epoch) override {
117 auto i = m_write_seqs.find(epoch);
118 if(i == m_write_seqs.end()) {
119 throw Invalid_State("DTLS epoch not found");
120 }
121 if(i->second > 0x0000FFFFFFFFFFFF) {
122 throw Invalid_State("DTLS write sequence number overflow");
123 }
124 return (static_cast<uint64_t>(epoch) << 48) | i->second++;
125 }
126
127 uint64_t next_read_sequence() override { throw Invalid_State("DTLS uses explicit sequence numbers"); }
128
129 bool already_seen(uint64_t sequence) const override {
130 const uint16_t epoch = static_cast<uint16_t>(sequence >> 48);
131 const uint64_t record_sequence = sequence & 0x0000FFFFFFFFFFFF;
132 const auto window = m_read_windows.find(epoch);
133
134 if(window == m_read_windows.end()) {
135 return false;
136 }
137
138 const size_t window_size = sizeof(window->second.bits) * 8;
139
140 if(record_sequence > window->second.highest) {
141 return false;
142 }
143
144 const uint64_t offset = window->second.highest - record_sequence;
145
146 if(offset >= window_size) {
147 return true; // really old?
148 }
149
150 return (((window->second.bits >> offset) & 1) == 1);
151 }
152
153 void read_accept(uint64_t sequence) override {
154 const uint16_t epoch = static_cast<uint16_t>(sequence >> 48);
155 const uint64_t record_sequence = sequence & 0x0000FFFFFFFFFFFF;
156 auto& window = m_read_windows[epoch];
157 const size_t window_size = sizeof(window.bits) * 8;
158
159 if(record_sequence > window.highest) {
160 // We've received a later sequence which advances our window
161 const uint64_t offset = record_sequence - window.highest;
162 window.highest += offset;
163
164 if(offset >= window_size) {
165 window.bits = 0;
166 } else {
167 window.bits <<= offset;
168 }
169
170 window.bits |= 0x01;
171 } else {
172 const uint64_t offset = window.highest - record_sequence;
173
174 if(offset < window_size) {
175 // We've received an old sequence but still within our window
176 window.bits |= (static_cast<uint64_t>(1) << offset);
177 } else {
178 // DTLS reconnection: recenter the window on this sequence. Bit 0
179 // marks the sequence itself as seen so an immediate replay is
180 // detected; the other branches above set this implicitly.
181 window.highest = record_sequence;
182 window.bits = 1;
183 }
184 }
185 }
186
187 private:
188 struct Replay_Window final {
189 uint64_t highest = 0;
190 uint64_t bits = 0;
191 };
192
193 /*
194 * RFC 6347 4.1: "Similarly, implementations MUST NOT allow the epoch to
195 * wrap, but instead MUST establish a new association, terminating the old
196 * association as described in Section 4.2.8."
197 *
198 * Throwing leaves the counters untouched; the channel turns it into a
199 * fatal alert, which is the termination the requirement asks for.
200 */
201 static uint16_t next_epoch(uint16_t epoch) {
202 if(epoch == std::numeric_limits<uint16_t>::max()) {
203 throw Invalid_State("DTLS epoch counter exhausted");
204 }
205 return static_cast<uint16_t>(epoch + 1);
206 }
207
208 /*
209 * Only the current epoch and the one it replaced can still carry traffic;
210 *
211 * The behavior of this function must match the value of TLS_RETAINED_CIPHERSTATES
212 * in tls_channel_impl_12.cpp
213 *
214 * Epoch 0 is exempt: a HelloVerifyRequest is written under it
215 * however many times the association has rekeyed.
216 */
217 template <typename T>
218 static void prune_epochs(std::map<uint16_t, T>& epochs, uint16_t current) {
219 for(auto i = epochs.begin(); i != epochs.end();) {
220 if(i->first == 0 || i->first + 1 >= current) {
221 ++i;
222 } else {
223 i = epochs.erase(i);
224 }
225 }
226 }
227
228 std::map<uint16_t, uint64_t> m_write_seqs;
229 std::map<uint16_t, Replay_Window> m_read_windows;
230 uint16_t m_write_epoch = 0;
231 uint16_t m_read_epoch = 0;
232};
233
234} // namespace Botan::TLS
235
236#endif
virtual uint16_t current_read_epoch() const =0
virtual ~Connection_Sequence_Numbers()=default
virtual void read_accept(uint64_t seq)=0
virtual uint16_t current_write_epoch() const =0
virtual bool already_seen(uint64_t seq) const =0
virtual uint64_t next_write_sequence(uint16_t)=0
void read_accept(uint64_t sequence) override
uint16_t current_read_epoch() const override
uint16_t current_write_epoch() const override
uint64_t next_write_sequence(uint16_t epoch) override
bool already_seen(uint64_t sequence) const override
uint64_t next_write_sequence(uint16_t) override
void read_accept(uint64_t) override
uint16_t current_read_epoch() const override
bool already_seen(uint64_t) const override
uint16_t current_write_epoch() const override