• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 4818131743

27 Apr 2023 09:55AM UTC coverage: 92.146%. Remained the same
4818131743

push

github

77594 of 84208 relevant lines covered (92.15%)

11896883.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.73
/src/lib/tls/tls12/tls_handshake_io.cpp
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/internal/tls_record.h>
11
#include <botan/internal/tls_seq_numbers.h>
12
#include <botan/tls_messages.h>
13
#include <botan/exceptn.h>
14
#include <botan/internal/loadstor.h>
15
#include <chrono>
16

17
namespace Botan::TLS {
18

19
namespace {
20

21
inline size_t load_be24(const uint8_t q[3])
178,541✔
22
   {
23
   return make_uint32(0,
178,541✔
24
                      q[0],
178,541✔
25
                      q[1],
178,541✔
26
                      q[2]);
178,541✔
27
   }
28

29
void store_be24(uint8_t out[3], size_t val)
19,596✔
30
   {
31
   out[0] = get_byte<1>(static_cast<uint32_t>(val));
19,596✔
32
   out[1] = get_byte<2>(static_cast<uint32_t>(val));
7,673✔
33
   out[2] = get_byte<3>(static_cast<uint32_t>(val));
19,596✔
34
   }
35

36
uint64_t steady_clock_ms()
3,348✔
37
   {
38
   return std::chrono::duration_cast<std::chrono::milliseconds>(
3,348✔
39
      std::chrono::steady_clock::now().time_since_epoch()).count();
3,348✔
40
   }
41

42
}
43

44
Protocol_Version Stream_Handshake_IO::initial_record_version() const
3,225✔
45
   {
46
   return Protocol_Version::TLS_V12;
3,225✔
47
   }
48

49
void Stream_Handshake_IO::add_record(const uint8_t record[],
111,298✔
50
                                     size_t record_len,
51
                                     Record_Type record_type, uint64_t /*sequence_number*/)
52
   {
53
   if(record_type == Record_Type::Handshake)
111,298✔
54
      {
55
      m_queue.insert(m_queue.end(), record, record + record_len);
110,233✔
56
      }
57
   else if(record_type == Record_Type::ChangeCipherSpec)
1,065✔
58
      {
59
      if(record_len != 1 || record[0] != 1)
1,065✔
60
         throw Decoding_Error("Invalid ChangeCipherSpec");
2✔
61

62
      // Pretend it's a regular handshake message of zero length
63
      const uint8_t ccs_hs[] = {
1,063✔
64
         static_cast<uint8_t>(Handshake_Type::HandshakeCCS), 0, 0, 0
65
      };
66
      m_queue.insert(m_queue.end(), ccs_hs, ccs_hs + sizeof(ccs_hs));
1,063✔
67
      }
68
   else
69
      throw Decoding_Error("Unknown message type " +
×
70
                           std::to_string(static_cast<size_t>(record_type)) +
×
71
                           " in handshake processing");
×
72
   }
111,296✔
73

74
std::pair<Handshake_Type, std::vector<uint8_t>>
75
Stream_Handshake_IO::get_next_record(bool /*expecting_ccs*/)
116,008✔
76
   {
77
   if(m_queue.size() >= 4)
116,008✔
78
      {
79
      const size_t length = 4 + make_uint32(0, m_queue[1], m_queue[2], m_queue[3]);
110,107✔
80

81
      if(m_queue.size() >= length)
110,107✔
82
         {
83
         Handshake_Type type = static_cast<Handshake_Type>(m_queue[0]);
7,296✔
84

85
         if(type == Handshake_Type::None)
7,296✔
86
            throw Decoding_Error("Invalid handshake message type");
×
87

88
         std::vector<uint8_t> contents(m_queue.begin() + 4,
7,296✔
89
                                       m_queue.begin() + length);
7,296✔
90

91
         m_queue.erase(m_queue.begin(), m_queue.begin() + length);
7,296✔
92

93
         return std::make_pair(type, contents);
14,592✔
94
         }
7,296✔
95
      }
96

97
   return std::make_pair(Handshake_Type::None, std::vector<uint8_t>());
108,712✔
98
   }
99

100
std::vector<uint8_t>
101
Stream_Handshake_IO::format(const std::vector<uint8_t>& msg,
11,923✔
102
                            Handshake_Type type) const
103
   {
104
   std::vector<uint8_t> send_buf(4 + msg.size());
11,923✔
105

106
   const size_t buf_size = msg.size();
11,923✔
107

108
   send_buf[0] = static_cast<uint8_t>(type);
11,923✔
109

110
   store_be24(&send_buf[1], buf_size);
11,923✔
111

112
   if (!msg.empty())
11,923✔
113
      {
114
      copy_mem(&send_buf[4], msg.data(), msg.size());
11,052✔
115
      }
116

117
   return send_buf;
11,923✔
118
   }
×
119

120
std::vector<uint8_t> Stream_Handshake_IO::send_under_epoch(const Handshake_Message& /*msg*/, uint16_t /*epoch*/)
×
121
   {
122
   throw Invalid_State("Not possible to send under arbitrary epoch with stream based TLS");
×
123
   }
124

125
std::vector<uint8_t> Stream_Handshake_IO::send(const Handshake_Message& msg)
6,972✔
126
   {
127
   const std::vector<uint8_t> msg_bits = msg.serialize();
6,972✔
128

129
   if(msg.type() == Handshake_Type::HandshakeCCS)
6,972✔
130
      {
131
      m_send_hs(Record_Type::ChangeCipherSpec, msg_bits);
1,048✔
132
      return std::vector<uint8_t>(); // not included in handshake hashes
1,048✔
133
      }
134

135
   auto buf = format(msg_bits, msg.wire_type());
5,924✔
136
   m_send_hs(Record_Type::Handshake, buf);
5,924✔
137
   return buf;
5,921✔
138
   }
13,542✔
139

140
Protocol_Version Datagram_Handshake_IO::initial_record_version() const
815✔
141
   {
142
   return Protocol_Version::DTLS_V12;
815✔
143
   }
144

145
void Datagram_Handshake_IO::retransmit_last_flight()
×
146
   {
147
   const size_t flight_idx = (m_flights.size() == 1) ? 0 : (m_flights.size() - 2);
×
148
   retransmit_flight(flight_idx);
×
149
   }
×
150

151
void Datagram_Handshake_IO::retransmit_flight(size_t flight_idx)
×
152
   {
153
   const std::vector<uint16_t>& flight = m_flights.at(flight_idx);
×
154

155
   BOTAN_ASSERT(!flight.empty(), "Nonempty flight to retransmit");
×
156

157
   uint16_t epoch = m_flight_data[flight[0]].epoch;
×
158

159
   for(auto msg_seq : flight)
×
160
      {
161
      auto& msg = m_flight_data[msg_seq];
×
162

163
      if(msg.epoch != epoch)
×
164
         {
165
         // Epoch gap: insert the CCS
166
         std::vector<uint8_t> ccs(1, 1);
×
167
         m_send_hs(epoch, Record_Type::ChangeCipherSpec, ccs);
×
168
         }
×
169

170
      send_message(msg_seq, msg.epoch, msg.msg_type, msg.msg_bits);
×
171
      epoch = msg.epoch;
×
172
      }
173
   }
×
174

175
bool Datagram_Handshake_IO::have_more_data() const
1,740✔
176
   {
177
   return false;
1,740✔
178
   }
179

180
bool Datagram_Handshake_IO::timeout_check()
×
181
   {
182
   if(m_last_write == 0 || (m_flights.size() > 1 && !m_flights.rbegin()->empty()))
×
183
      {
184
      /*
185
      If we haven't written anything yet obviously no timeout.
186
      Also no timeout possible if we are mid-flight,
187
      */
188
      return false;
189
      }
190

191
   const uint64_t ms_since_write = steady_clock_ms() - m_last_write;
×
192

193
   if(ms_since_write < m_next_timeout)
×
194
      return false;
195

196
   retransmit_last_flight();
×
197

198
   m_next_timeout = std::min(2 * m_next_timeout, m_max_timeout);
×
199
   return true;
×
200
   }
201

202
void Datagram_Handshake_IO::add_record(const uint8_t record[],
179,251✔
203
                                       size_t record_len,
204
                                       Record_Type record_type,
205
                                       uint64_t record_sequence)
206
   {
207
   const uint16_t epoch = static_cast<uint16_t>(record_sequence >> 48);
179,251✔
208

209
   if(record_type == Record_Type::ChangeCipherSpec)
179,251✔
210
      {
211
      if(record_len != 1 || record[0] != 1)
709✔
212
         throw Decoding_Error("Invalid ChangeCipherSpec");
2✔
213

214
      // TODO: check this is otherwise empty
215
      m_ccs_epochs.insert(epoch);
707✔
216
      return;
708✔
217
      }
218

219
   const size_t DTLS_HANDSHAKE_HEADER_LEN = 12;
220

221
   while(record_len)
357,078✔
222
      {
223
      if(record_len < DTLS_HANDSHAKE_HEADER_LEN)
178,542✔
224
         return; // completely bogus? at least degenerate/weird
1✔
225

226
      const Handshake_Type msg_type = static_cast<Handshake_Type>(record[0]);
178,541✔
227
      const size_t msg_len = load_be24(&record[1]);
178,541✔
228
      const uint16_t message_seq = load_be<uint16_t>(&record[4], 0);
178,541✔
229
      const size_t fragment_offset = load_be24(&record[6]);
178,541✔
230
      const size_t fragment_length = load_be24(&record[9]);
178,541✔
231

232
      const size_t total_size = DTLS_HANDSHAKE_HEADER_LEN + fragment_length;
178,541✔
233

234
      if(record_len < total_size)
178,541✔
235
         throw Decoding_Error("Bad lengths in DTLS header");
3✔
236

237
      if(message_seq >= m_in_message_seq)
178,538✔
238
         {
239
         m_messages[message_seq].add_fragment(&record[DTLS_HANDSHAKE_HEADER_LEN],
177,794✔
240
                                              fragment_length,
241
                                              fragment_offset,
242
                                              epoch,
243
                                              msg_type,
244
                                              msg_len);
245
         }
246
      else
247
         {
248
         // TODO: detect retransmitted flight
249
         }
250

251
      record += total_size;
178,536✔
252
      record_len -= total_size;
178,536✔
253
      }
254
   }
255

256
std::pair<Handshake_Type, std::vector<uint8_t>>
257
Datagram_Handshake_IO::get_next_record(bool expecting_ccs)
183,076✔
258
   {
259
   // Expecting a message means the last flight is concluded
260
   if(!m_flights.rbegin()->empty())
183,076✔
261
      m_flights.push_back(std::vector<uint16_t>());
1,506✔
262

263
   if(expecting_ccs)
183,076✔
264
      {
265
      if(!m_messages.empty())
1,578✔
266
         {
267
         const uint16_t current_epoch = m_messages.begin()->second.epoch();
1,578✔
268

269
         if(m_ccs_epochs.contains(current_epoch))
3,156✔
270
            return std::make_pair(Handshake_Type::HandshakeCCS, std::vector<uint8_t>());
701✔
271
         }
272
      return std::make_pair(Handshake_Type::None, std::vector<uint8_t>());
877✔
273
      }
274

275
   auto i = m_messages.find(m_in_message_seq);
181,498✔
276

277
   if(i == m_messages.end() || !i->second.complete())
181,498✔
278
      {
279
      return std::make_pair(Handshake_Type::None, std::vector<uint8_t>());
177,570✔
280
      }
281

282
   m_in_message_seq += 1;
3,928✔
283

284
   return i->second.message();
3,928✔
285
   }
286

287
void Datagram_Handshake_IO::Handshake_Reassembly::add_fragment(
177,794✔
288
   const uint8_t fragment[],
289
   size_t fragment_length,
290
   size_t fragment_offset,
291
   uint16_t epoch,
292
   Handshake_Type msg_type,
293
   size_t msg_length)
294
   {
295
   if(complete())
533,243✔
296
      return; // already have entire message, ignore this
297

298
   if(m_msg_type == Handshake_Type::None)
177,657✔
299
      {
300
      m_epoch = epoch;
3,933✔
301
      m_msg_type = msg_type;
3,933✔
302
      m_msg_length = msg_length;
3,933✔
303
      }
304

305
   if(msg_type != m_msg_type || msg_length != m_msg_length || epoch != m_epoch)
177,657✔
306
      throw Decoding_Error("Inconsistent values in fragmented DTLS handshake header");
2✔
307

308
   if(fragment_offset > m_msg_length)
177,655✔
309
      throw Decoding_Error("Fragment offset past end of message");
×
310

311
   if(fragment_offset + fragment_length > m_msg_length)
177,655✔
312
      throw Decoding_Error("Fragment overlaps past end of message");
×
313

314
   if(fragment_offset == 0 && fragment_length == m_msg_length)
177,655✔
315
      {
316
      m_fragments.clear();
2,916✔
317
      m_message.assign(fragment, fragment+fragment_length);
2,916✔
318
      }
319
   else
320
      {
321
      /*
322
      * FIXME. This is a pretty lame way to do defragmentation, huge
323
      * overhead with a tree node per byte.
324
      *
325
      * Also should confirm that all overlaps have no changes,
326
      * otherwise we expose ourselves to the classic fingerprinting
327
      * and IDS evasion attacks on IP fragmentation.
328
      */
329
      for(size_t i = 0; i != fragment_length; ++i)
541,400✔
330
         m_fragments[fragment_offset+i] = fragment[i];
366,661✔
331

332
      if(m_fragments.size() == m_msg_length)
174,739✔
333
         {
334
         m_message.resize(m_msg_length);
1,013✔
335
         for(size_t i = 0; i != m_msg_length; ++i)
359,817✔
336
            m_message[i] = m_fragments[i];
358,804✔
337
         m_fragments.clear();
178,805✔
338
         }
339
      }
340
   }
341

342
bool Datagram_Handshake_IO::Handshake_Reassembly::complete() const
359,440✔
343
   {
344
   return (m_msg_type != Handshake_Type::None &&
359,440✔
345
           m_message.size() == m_msg_length);
355,507✔
346
   }
347

348
std::pair<Handshake_Type, std::vector<uint8_t>>
349
Datagram_Handshake_IO::Handshake_Reassembly::message() const
3,928✔
350
   {
351
   if(!complete())
3,928✔
352
      throw Internal_Error("Datagram_Handshake_IO - message not complete");
×
353

354
   return std::make_pair(m_msg_type, m_message);
3,928✔
355
   }
356

357
std::vector<uint8_t>
358
Datagram_Handshake_IO::format_fragment(const uint8_t fragment[],
7,673✔
359
                                       size_t frag_len,
360
                                       uint16_t frag_offset,
361
                                       uint16_t msg_len,
362
                                       Handshake_Type type,
363
                                       uint16_t msg_sequence) const
364
   {
365
   std::vector<uint8_t> send_buf(12 + frag_len);
7,673✔
366

367
   send_buf[0] = static_cast<uint8_t>(type);
7,673✔
368

369
   store_be24(&send_buf[1], msg_len);
7,673✔
370

371
   store_be(msg_sequence, &send_buf[4]);
7,673✔
372

373
   store_be24(&send_buf[6], frag_offset);
7,673✔
374
   store_be24(&send_buf[9], frag_len);
7,673✔
375

376
   if (frag_len > 0)
7,673✔
377
      {
378
      copy_mem(&send_buf[12], fragment, frag_len);
7,112✔
379
      }
380

381
   return send_buf;
7,673✔
382
   }
×
383

384
std::vector<uint8_t>
385
Datagram_Handshake_IO::format_w_seq(const std::vector<uint8_t>& msg,
7,107✔
386
                                    Handshake_Type type,
387
                                    uint16_t msg_sequence) const
388
   {
389
   return format_fragment(msg.data(), msg.size(), 0, static_cast<uint16_t>(msg.size()), type, msg_sequence);
×
390
   }
391

392
std::vector<uint8_t>
393
Datagram_Handshake_IO::format(const std::vector<uint8_t>& msg,
3,392✔
394
                              Handshake_Type type) const
395
   {
396
   return format_w_seq(msg, type, m_in_message_seq - 1);
3,392✔
397
   }
398

399
std::vector<uint8_t> Datagram_Handshake_IO::send(const Handshake_Message& msg)
4,417✔
400
   {
401
   return this->send_under_epoch(msg, m_seqs.current_write_epoch());
4,417✔
402
   }
403

404
std::vector<uint8_t>
405
Datagram_Handshake_IO::send_under_epoch(const Handshake_Message& msg, uint16_t epoch)
4,418✔
406
   {
407
   const std::vector<uint8_t> msg_bits = msg.serialize();
4,418✔
408
   const Handshake_Type msg_type = msg.type();
4,418✔
409

410
   if(msg_type == Handshake_Type::HandshakeCCS)
4,418✔
411
      {
412
      m_send_hs(epoch, Record_Type::ChangeCipherSpec, msg_bits);
703✔
413
      return std::vector<uint8_t>(); // not included in handshake hashes
703✔
414
      }
415
   else if(msg_type == Handshake_Type::HelloVerifyRequest)
3,715✔
416
      {
417
      // This message is not included in the handshake hashes
418
      send_message(m_out_message_seq, epoch, msg_type, msg_bits);
367✔
419
      m_out_message_seq += 1;
367✔
420
      return std::vector<uint8_t>();
4,418✔
421
      }
422

423
   // Note: not saving CCS, instead we know it was there due to change in epoch
424
   m_flights.rbegin()->push_back(m_out_message_seq);
3,348✔
425
   m_flight_data[m_out_message_seq] = Message_Info(epoch, msg_type, msg_bits);
3,348✔
426

427
   m_out_message_seq += 1;
3,348✔
428
   m_last_write = steady_clock_ms();
3,348✔
429
   m_next_timeout = m_initial_timeout;
3,348✔
430

431
   return send_message(m_out_message_seq - 1, epoch, msg_type, msg_bits);
3,348✔
432
   }
4,418✔
433

434
std::vector<uint8_t> Datagram_Handshake_IO::send_message(uint16_t msg_seq,
3,715✔
435
                                                      uint16_t epoch,
436
                                                      Handshake_Type msg_type,
437
                                                      const std::vector<uint8_t>& msg_bits)
438
   {
439
   const size_t DTLS_HANDSHAKE_HEADER_LEN = 12;
3,715✔
440

441
   auto no_fragment = format_w_seq(msg_bits, msg_type, msg_seq);
3,715✔
442

443
   if(no_fragment.size() + DTLS_HEADER_SIZE <= m_mtu)
3,715✔
444
      {
445
      m_send_hs(epoch, Record_Type::Handshake, no_fragment);
7,038✔
446
      }
447
   else
448
      {
449
      size_t frag_offset = 0;
196✔
450

451
      /**
452
      * Largest possible overhead is for SHA-384 CBC ciphers, with 16 byte IV,
453
      * 16+ for padding and 48 bytes for MAC. 128 is probably a strict
454
      * over-estimate here. When CBC ciphers are removed this can be reduced
455
      * since AEAD modes have no padding, at most 16 byte mac, and smaller
456
      * per-record nonce.
457
      */
458
      const size_t ciphersuite_overhead = (epoch > 0) ? 128 : 0;
196✔
459
      const size_t header_overhead = DTLS_HEADER_SIZE + DTLS_HANDSHAKE_HEADER_LEN;
196✔
460

461
      if(m_mtu <= (header_overhead + ciphersuite_overhead))
196✔
462
         throw Invalid_Argument("DTLS MTU is too small to send headers");
×
463

464
      const size_t max_rec_size = m_mtu - (header_overhead + ciphersuite_overhead);
196✔
465

466
      while(frag_offset != msg_bits.size())
762✔
467
         {
468
         const size_t frag_len = std::min<size_t>(msg_bits.size() - frag_offset, max_rec_size);
566✔
469

470
         const std::vector<uint8_t> frag =
566✔
471
            format_fragment(&msg_bits[frag_offset],
566✔
472
                            frag_len,
473
                            static_cast<uint16_t>(frag_offset),
474
                            static_cast<uint16_t>(msg_bits.size()),
566✔
475
                            msg_type,
476
                            msg_seq);
566✔
477

478
         m_send_hs(epoch, Record_Type::Handshake, frag);
566✔
479

480
         frag_offset += frag_len;
566✔
481
         }
566✔
482
      }
483

484
   return no_fragment;
3,715✔
485
   }
×
486

487
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc