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