Botan 3.3.0
Crypto and TLS for C&
tls_handshake_io.cpp
Go to the documentation of this file.
1/*
2* TLS Handshake IO
3* (C) 2012,2014,2015 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/internal/tls_handshake_io.h>
9
10#include <botan/exceptn.h>
11#include <botan/tls_messages.h>
12#include <botan/internal/loadstor.h>
13#include <botan/internal/tls_record.h>
14#include <botan/internal/tls_seq_numbers.h>
15#include <chrono>
16
17namespace Botan::TLS {
18
19namespace {
20
21inline size_t load_be24(const uint8_t q[3]) {
22 return make_uint32(0, q[0], q[1], q[2]);
23}
24
25void store_be24(uint8_t out[3], size_t val) {
26 out[0] = get_byte<1>(static_cast<uint32_t>(val));
27 out[1] = get_byte<2>(static_cast<uint32_t>(val));
28 out[2] = get_byte<3>(static_cast<uint32_t>(val));
29}
30
31uint64_t steady_clock_ms() {
32 return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch())
33 .count();
34}
35
36} // namespace
37
39 return Protocol_Version::TLS_V12;
40}
41
42void Stream_Handshake_IO::add_record(const uint8_t record[],
43 size_t record_len,
44 Record_Type record_type,
45 uint64_t /*sequence_number*/) {
46 if(record_type == Record_Type::Handshake) {
47 m_queue.insert(m_queue.end(), record, record + record_len);
48 } else if(record_type == Record_Type::ChangeCipherSpec) {
49 if(record_len != 1 || record[0] != 1) {
50 throw Decoding_Error("Invalid ChangeCipherSpec");
51 }
52
53 // Pretend it's a regular handshake message of zero length
54 const uint8_t ccs_hs[] = {static_cast<uint8_t>(Handshake_Type::HandshakeCCS), 0, 0, 0};
55 m_queue.insert(m_queue.end(), ccs_hs, ccs_hs + sizeof(ccs_hs));
56 } else {
57 throw Decoding_Error("Unknown message type " + std::to_string(static_cast<size_t>(record_type)) +
58 " in handshake processing");
59 }
60}
61
62std::pair<Handshake_Type, std::vector<uint8_t>> Stream_Handshake_IO::get_next_record(bool /*expecting_ccs*/) {
63 if(m_queue.size() >= 4) {
64 const size_t length = 4 + make_uint32(0, m_queue[1], m_queue[2], m_queue[3]);
65
66 if(m_queue.size() >= length) {
67 Handshake_Type type = static_cast<Handshake_Type>(m_queue[0]);
68
69 if(type == Handshake_Type::None) {
70 throw Decoding_Error("Invalid handshake message type");
71 }
72
73 std::vector<uint8_t> contents(m_queue.begin() + 4, m_queue.begin() + length);
74
75 m_queue.erase(m_queue.begin(), m_queue.begin() + length);
76
77 return std::make_pair(type, contents);
78 }
79 }
80
81 return std::make_pair(Handshake_Type::None, std::vector<uint8_t>());
82}
83
84std::vector<uint8_t> Stream_Handshake_IO::format(const std::vector<uint8_t>& msg, Handshake_Type type) const {
85 std::vector<uint8_t> send_buf(4 + msg.size());
86
87 const size_t buf_size = msg.size();
88
89 send_buf[0] = static_cast<uint8_t>(type);
90
91 store_be24(&send_buf[1], buf_size);
92
93 if(!msg.empty()) {
94 copy_mem(&send_buf[4], msg.data(), msg.size());
95 }
96
97 return send_buf;
98}
99
100std::vector<uint8_t> Stream_Handshake_IO::send_under_epoch(const Handshake_Message& /*msg*/, uint16_t /*epoch*/) {
101 throw Invalid_State("Not possible to send under arbitrary epoch with stream based TLS");
102}
103
104std::vector<uint8_t> Stream_Handshake_IO::send(const Handshake_Message& msg) {
105 const std::vector<uint8_t> msg_bits = msg.serialize();
106
108 m_send_hs(Record_Type::ChangeCipherSpec, msg_bits);
109 return std::vector<uint8_t>(); // not included in handshake hashes
110 }
111
112 auto buf = format(msg_bits, msg.wire_type());
113 m_send_hs(Record_Type::Handshake, buf);
114 return buf;
115}
116
118 return Protocol_Version::DTLS_V12;
119}
120
121void Datagram_Handshake_IO::retransmit_last_flight() {
122 const size_t flight_idx = (m_flights.size() == 1) ? 0 : (m_flights.size() - 2);
123 retransmit_flight(flight_idx);
124}
125
126void Datagram_Handshake_IO::retransmit_flight(size_t flight_idx) {
127 const std::vector<uint16_t>& flight = m_flights.at(flight_idx);
128
129 BOTAN_ASSERT(!flight.empty(), "Nonempty flight to retransmit");
130
131 uint16_t epoch = m_flight_data[flight[0]].epoch;
132
133 for(auto msg_seq : flight) {
134 auto& msg = m_flight_data[msg_seq];
135
136 if(msg.epoch != epoch) {
137 // Epoch gap: insert the CCS
138 std::vector<uint8_t> ccs(1, 1);
139 m_send_hs(epoch, Record_Type::ChangeCipherSpec, ccs);
140 }
141
142 send_message(msg_seq, msg.epoch, msg.msg_type, msg.msg_bits);
143 epoch = msg.epoch;
144 }
145}
146
148 return false;
149}
150
152 if(m_last_write == 0 || (m_flights.size() > 1 && !m_flights.rbegin()->empty())) {
153 /*
154 If we haven't written anything yet obviously no timeout.
155 Also no timeout possible if we are mid-flight,
156 */
157 return false;
158 }
159
160 const uint64_t ms_since_write = steady_clock_ms() - m_last_write;
161
162 if(ms_since_write < m_next_timeout) {
163 return false;
164 }
165
166 retransmit_last_flight();
167
168 m_next_timeout = std::min(2 * m_next_timeout, m_max_timeout);
169 return true;
170}
171
172void Datagram_Handshake_IO::add_record(const uint8_t record[],
173 size_t record_len,
174 Record_Type record_type,
175 uint64_t record_sequence) {
176 const uint16_t epoch = static_cast<uint16_t>(record_sequence >> 48);
177
178 if(record_type == Record_Type::ChangeCipherSpec) {
179 if(record_len != 1 || record[0] != 1) {
180 throw Decoding_Error("Invalid ChangeCipherSpec");
181 }
182
183 // TODO: check this is otherwise empty
184 m_ccs_epochs.insert(epoch);
185 return;
186 }
187
188 const size_t DTLS_HANDSHAKE_HEADER_LEN = 12;
189
190 while(record_len) {
191 if(record_len < DTLS_HANDSHAKE_HEADER_LEN) {
192 return; // completely bogus? at least degenerate/weird
193 }
194
195 const Handshake_Type msg_type = static_cast<Handshake_Type>(record[0]);
196 const size_t msg_len = load_be24(&record[1]);
197 const uint16_t message_seq = load_be<uint16_t>(&record[4], 0);
198 const size_t fragment_offset = load_be24(&record[6]);
199 const size_t fragment_length = load_be24(&record[9]);
200
201 const size_t total_size = DTLS_HANDSHAKE_HEADER_LEN + fragment_length;
202
203 if(record_len < total_size) {
204 throw Decoding_Error("Bad lengths in DTLS header");
205 }
206
207 if(message_seq >= m_in_message_seq) {
208 m_messages[message_seq].add_fragment(
209 &record[DTLS_HANDSHAKE_HEADER_LEN], fragment_length, fragment_offset, epoch, msg_type, msg_len);
210 } else {
211 // TODO: detect retransmitted flight
212 }
213
214 record += total_size;
215 record_len -= total_size;
216 }
217}
218
219std::pair<Handshake_Type, std::vector<uint8_t>> Datagram_Handshake_IO::get_next_record(bool expecting_ccs) {
220 // Expecting a message means the last flight is concluded
221 if(!m_flights.rbegin()->empty()) {
222 m_flights.push_back(std::vector<uint16_t>());
223 }
224
225 if(expecting_ccs) {
226 if(!m_messages.empty()) {
227 const uint16_t current_epoch = m_messages.begin()->second.epoch();
228
229 if(m_ccs_epochs.contains(current_epoch)) {
230 return std::make_pair(Handshake_Type::HandshakeCCS, std::vector<uint8_t>());
231 }
232 }
233 return std::make_pair(Handshake_Type::None, std::vector<uint8_t>());
234 }
235
236 auto i = m_messages.find(m_in_message_seq);
237
238 if(i == m_messages.end() || !i->second.complete()) {
239 return std::make_pair(Handshake_Type::None, std::vector<uint8_t>());
240 }
241
242 m_in_message_seq += 1;
243
244 return i->second.message();
245}
246
247void Datagram_Handshake_IO::Handshake_Reassembly::add_fragment(const uint8_t fragment[],
248 size_t fragment_length,
249 size_t fragment_offset,
250 uint16_t epoch,
251 Handshake_Type msg_type,
252 size_t msg_length) {
253 if(complete()) {
254 return; // already have entire message, ignore this
255 }
256
257 if(m_msg_type == Handshake_Type::None) {
258 m_epoch = epoch;
259 m_msg_type = msg_type;
260 m_msg_length = msg_length;
261 }
262
263 if(msg_type != m_msg_type || msg_length != m_msg_length || epoch != m_epoch) {
264 throw Decoding_Error("Inconsistent values in fragmented DTLS handshake header");
265 }
266
267 if(fragment_offset > m_msg_length) {
268 throw Decoding_Error("Fragment offset past end of message");
269 }
270
271 if(fragment_offset + fragment_length > m_msg_length) {
272 throw Decoding_Error("Fragment overlaps past end of message");
273 }
274
275 if(fragment_offset == 0 && fragment_length == m_msg_length) {
276 m_fragments.clear();
277 m_message.assign(fragment, fragment + fragment_length);
278 } else {
279 /*
280 * FIXME. This is a pretty lame way to do defragmentation, huge
281 * overhead with a tree node per byte.
282 *
283 * Also should confirm that all overlaps have no changes,
284 * otherwise we expose ourselves to the classic fingerprinting
285 * and IDS evasion attacks on IP fragmentation.
286 */
287 for(size_t i = 0; i != fragment_length; ++i) {
288 m_fragments[fragment_offset + i] = fragment[i];
289 }
290
291 if(m_fragments.size() == m_msg_length) {
292 m_message.resize(m_msg_length);
293 for(size_t i = 0; i != m_msg_length; ++i) {
294 m_message[i] = m_fragments[i];
295 }
296 m_fragments.clear();
297 }
298 }
299}
300
301bool Datagram_Handshake_IO::Handshake_Reassembly::complete() const {
302 return (m_msg_type != Handshake_Type::None && m_message.size() == m_msg_length);
303}
304
305std::pair<Handshake_Type, std::vector<uint8_t>> Datagram_Handshake_IO::Handshake_Reassembly::message() const {
306 if(!complete()) {
307 throw Internal_Error("Datagram_Handshake_IO - message not complete");
308 }
309
310 return std::make_pair(m_msg_type, m_message);
311}
312
313std::vector<uint8_t> Datagram_Handshake_IO::format_fragment(const uint8_t fragment[],
314 size_t frag_len,
315 uint16_t frag_offset,
316 uint16_t msg_len,
317 Handshake_Type type,
318 uint16_t msg_sequence) const {
319 std::vector<uint8_t> send_buf(12 + frag_len);
320
321 send_buf[0] = static_cast<uint8_t>(type);
322
323 store_be24(&send_buf[1], msg_len);
324
325 store_be(msg_sequence, &send_buf[4]);
326
327 store_be24(&send_buf[6], frag_offset);
328 store_be24(&send_buf[9], frag_len);
329
330 if(frag_len > 0) {
331 copy_mem(&send_buf[12], fragment, frag_len);
332 }
333
334 return send_buf;
335}
336
337std::vector<uint8_t> Datagram_Handshake_IO::format_w_seq(const std::vector<uint8_t>& msg,
338 Handshake_Type type,
339 uint16_t msg_sequence) const {
340 return format_fragment(msg.data(), msg.size(), 0, static_cast<uint16_t>(msg.size()), type, msg_sequence);
341}
342
343std::vector<uint8_t> Datagram_Handshake_IO::format(const std::vector<uint8_t>& msg, Handshake_Type type) const {
344 return format_w_seq(msg, type, m_in_message_seq - 1);
345}
346
347std::vector<uint8_t> Datagram_Handshake_IO::send(const Handshake_Message& msg) {
348 return this->send_under_epoch(msg, m_seqs.current_write_epoch());
349}
350
351std::vector<uint8_t> Datagram_Handshake_IO::send_under_epoch(const Handshake_Message& msg, uint16_t epoch) {
352 const std::vector<uint8_t> msg_bits = msg.serialize();
353 const Handshake_Type msg_type = msg.type();
354
355 if(msg_type == Handshake_Type::HandshakeCCS) {
356 m_send_hs(epoch, Record_Type::ChangeCipherSpec, msg_bits);
357 return std::vector<uint8_t>(); // not included in handshake hashes
358 } else if(msg_type == Handshake_Type::HelloVerifyRequest) {
359 // This message is not included in the handshake hashes
360 send_message(m_out_message_seq, epoch, msg_type, msg_bits);
361 m_out_message_seq += 1;
362 return std::vector<uint8_t>();
363 }
364
365 // Note: not saving CCS, instead we know it was there due to change in epoch
366 m_flights.rbegin()->push_back(m_out_message_seq);
367 m_flight_data[m_out_message_seq] = Message_Info(epoch, msg_type, msg_bits);
368
369 m_out_message_seq += 1;
370 m_last_write = steady_clock_ms();
371 m_next_timeout = m_initial_timeout;
372
373 return send_message(m_out_message_seq - 1, epoch, msg_type, msg_bits);
374}
375
376std::vector<uint8_t> Datagram_Handshake_IO::send_message(uint16_t msg_seq,
377 uint16_t epoch,
378 Handshake_Type msg_type,
379 const std::vector<uint8_t>& msg_bits) {
380 const size_t DTLS_HANDSHAKE_HEADER_LEN = 12;
381
382 auto no_fragment = format_w_seq(msg_bits, msg_type, msg_seq);
383
384 if(no_fragment.size() + DTLS_HEADER_SIZE <= m_mtu) {
385 m_send_hs(epoch, Record_Type::Handshake, no_fragment);
386 } else {
387 size_t frag_offset = 0;
388
389 /**
390 * Largest possible overhead is for SHA-384 CBC ciphers, with 16 byte IV,
391 * 16+ for padding and 48 bytes for MAC. 128 is probably a strict
392 * over-estimate here. When CBC ciphers are removed this can be reduced
393 * since AEAD modes have no padding, at most 16 byte mac, and smaller
394 * per-record nonce.
395 */
396 const size_t ciphersuite_overhead = (epoch > 0) ? 128 : 0;
397 const size_t header_overhead = DTLS_HEADER_SIZE + DTLS_HANDSHAKE_HEADER_LEN;
398
399 if(m_mtu <= (header_overhead + ciphersuite_overhead)) {
400 throw Invalid_Argument("DTLS MTU is too small to send headers");
401 }
402
403 const size_t max_rec_size = m_mtu - (header_overhead + ciphersuite_overhead);
404
405 while(frag_offset != msg_bits.size()) {
406 const size_t frag_len = std::min<size_t>(msg_bits.size() - frag_offset, max_rec_size);
407
408 const std::vector<uint8_t> frag = format_fragment(&msg_bits[frag_offset],
409 frag_len,
410 static_cast<uint16_t>(frag_offset),
411 static_cast<uint16_t>(msg_bits.size()),
412 msg_type,
413 msg_seq);
414
415 m_send_hs(epoch, Record_Type::Handshake, frag);
416
417 frag_offset += frag_len;
418 }
419 }
420
421 return no_fragment;
422}
423
424} // namespace Botan::TLS
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:50
virtual uint16_t current_write_epoch() const =0
std::vector< uint8_t > send_under_epoch(const Handshake_Message &msg, uint16_t epoch) override
void add_record(const uint8_t record[], size_t record_len, Record_Type type, uint64_t sequence_number) override
std::pair< Handshake_Type, std::vector< uint8_t > > get_next_record(bool expecting_ccs) override
std::vector< uint8_t > format(const std::vector< uint8_t > &handshake_msg, Handshake_Type handshake_type) const override
Protocol_Version initial_record_version() const override
std::vector< uint8_t > send(const Handshake_Message &msg) override
virtual Handshake_Type type() const =0
virtual std::vector< uint8_t > serialize() const =0
virtual Handshake_Type wire_type() const
std::vector< uint8_t > send_under_epoch(const Handshake_Message &msg, uint16_t epoch) override
std::vector< uint8_t > format(const std::vector< uint8_t > &handshake_msg, Handshake_Type handshake_type) const override
Protocol_Version initial_record_version() const override
std::pair< Handshake_Type, std::vector< uint8_t > > get_next_record(bool expecting_ccs) override
std::vector< uint8_t > send(const Handshake_Message &msg) override
void add_record(const uint8_t record[], size_t record_len, Record_Type type, uint64_t sequence_number) override
@ DTLS_HEADER_SIZE
Definition tls_magic.h:26
constexpr void store_be(T in, OutR &&out_range)
Definition loadstor.h:358
constexpr uint32_t make_uint32(uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3)
Definition loadstor.h:62
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:146