Botan 3.12.0
Crypto and TLS for C&
Botan::TLS::Datagram_Handshake_IO Class Referencefinal

#include <tls_handshake_io.h>

Inheritance diagram for Botan::TLS::Datagram_Handshake_IO:
Botan::TLS::Handshake_IO

Public Types

typedef std::function< void(uint16_t, Record_Type, const std::vector< uint8_t > &)> writer_fn

Public Member Functions

void add_record (const uint8_t record[], size_t record_len, Record_Type type, uint64_t sequence_number) override
 Datagram_Handshake_IO (writer_fn writer, class Connection_Sequence_Numbers &seq, uint16_t mtu, uint64_t initial_timeout_ms, uint64_t max_timeout_ms, size_t max_handshake_msg_size)
std::vector< uint8_t > format (const std::vector< uint8_t > &handshake_msg, Handshake_Type handshake_type) const override
std::pair< Handshake_Type, std::vector< uint8_t > > get_next_record (bool expecting_ccs, size_t max_message_size) override
bool have_more_data () const override
Protocol_Version initial_record_version () const override
std::vector< uint8_t > send (const Handshake_Message &msg) override
std::vector< uint8_t > send_under_epoch (const Handshake_Message &msg, uint16_t epoch) override
bool timeout_check () override

Detailed Description

Handshake IO for datagram-based handshakes

Definition at line 114 of file tls_handshake_io.h.

Member Typedef Documentation

◆ writer_fn

typedef std::function<void(uint16_t, Record_Type, const std::vector<uint8_t>&)> Botan::TLS::Datagram_Handshake_IO::writer_fn

Definition at line 116 of file tls_handshake_io.h.

Constructor & Destructor Documentation

◆ Datagram_Handshake_IO()

Botan::TLS::Datagram_Handshake_IO::Datagram_Handshake_IO ( writer_fn writer,
class Connection_Sequence_Numbers & seq,
uint16_t mtu,
uint64_t initial_timeout_ms,
uint64_t max_timeout_ms,
size_t max_handshake_msg_size )
inline

Definition at line 118 of file tls_handshake_io.h.

123 :
124 m_seqs(seq),
125 m_flights(1),
126 m_initial_timeout(initial_timeout_ms),
127 m_max_timeout(max_timeout_ms),
128 m_send_hs(std::move(writer)),
129 m_mtu(mtu),
130 m_max_handshake_msg_size(max_handshake_msg_size) {}

Member Function Documentation

◆ add_record()

void Botan::TLS::Datagram_Handshake_IO::add_record ( const uint8_t record[],
size_t record_len,
Record_Type type,
uint64_t sequence_number )
overridevirtual

Implements Botan::TLS::Handshake_IO.

Definition at line 204 of file tls_handshake_io.cpp.

207 {
208 const uint16_t epoch = static_cast<uint16_t>(record_sequence >> 48);
209
210 if(record_type == Record_Type::ChangeCipherSpec) {
211 if(record_len != 1 || record[0] != 1) {
212 throw Decoding_Error("Invalid ChangeCipherSpec");
213 }
214
215 // TODO: check this is otherwise empty
216 m_ccs_epochs.insert(epoch);
217 return;
218 }
219
220 const size_t DTLS_HANDSHAKE_HEADER_LEN = 12;
221
222 while(record_len > 0) {
223 if(record_len < DTLS_HANDSHAKE_HEADER_LEN) {
224 return; // completely bogus? at least degenerate/weird
225 }
226
227 const Handshake_Type msg_type = static_cast<Handshake_Type>(record[0]);
228
229 verify_is_expected_wire_handshake_type(msg_type);
230
231 const size_t msg_len = load_be24(&record[1]);
232
233 if(m_max_handshake_msg_size > 0 && msg_len > m_max_handshake_msg_size) {
234 throw TLS_Exception(
235 Alert::HandshakeFailure,
236 Botan::fmt("Handshake message is {} bytes, policy maximum is {}", msg_len, m_max_handshake_msg_size));
237 }
238
239 const uint16_t message_seq = load_be<uint16_t>(&record[4], 0);
240 const size_t fragment_offset = load_be24(&record[6]);
241 const size_t fragment_length = load_be24(&record[9]);
242
243 const size_t total_size = DTLS_HANDSHAKE_HEADER_LEN + fragment_length;
244
245 if(record_len < total_size) {
246 throw Decoding_Error("Bad lengths in DTLS header");
247 }
248
249 // Bound the out-of-order reassembly window.
250 constexpr uint16_t reassembly_window = 16;
251
252 // Independently cap total bytes committed to in-flight reassembly slots
253 const size_t max_pending = 4 * m_max_handshake_msg_size;
254
255 if(message_seq >= m_in_message_seq && (message_seq - m_in_message_seq) < reassembly_window) {
256 auto [it, inserted] = m_messages.try_emplace(message_seq);
257 if(inserted) {
258 if(m_max_handshake_msg_size > 0 && m_pending_reassembly_bytes + msg_len > max_pending) {
259 m_messages.erase(it);
260 record += total_size;
261 record_len -= total_size;
262 continue;
263 }
264 m_pending_reassembly_bytes += msg_len;
265 }
266 it->second.add_fragment(
267 &record[DTLS_HANDSHAKE_HEADER_LEN], fragment_length, fragment_offset, epoch, msg_type, msg_len);
268 } else {
269 // TODO: detect retransmitted flight
270 }
271
272 record += total_size;
273 record_len -= total_size;
274 }
275}
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
constexpr auto load_be(ParamTs &&... params)
Definition loadstor.h:504

References Botan::TLS::ChangeCipherSpec, Botan::fmt(), and Botan::load_be().

◆ format()

std::vector< uint8_t > Botan::TLS::Datagram_Handshake_IO::format ( const std::vector< uint8_t > & handshake_msg,
Handshake_Type handshake_type ) const
overridevirtual

Implements Botan::TLS::Handshake_IO.

Definition at line 414 of file tls_handshake_io.cpp.

414 {
415 BOTAN_ASSERT_NOMSG(m_in_message_seq > 0);
416 return format_w_seq(msg, type, m_in_message_seq - 1);
417}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75

References BOTAN_ASSERT_NOMSG.

◆ get_next_record()

std::pair< Handshake_Type, std::vector< uint8_t > > Botan::TLS::Datagram_Handshake_IO::get_next_record ( bool expecting_ccs,
size_t max_message_size )
overridevirtual

Returns (HANDSHAKE_NONE, std::vector<>()) if no message currently available

Implements Botan::TLS::Handshake_IO.

Definition at line 277 of file tls_handshake_io.cpp.

278 {
279 // Expecting a message means the last flight is concluded
280 if(!m_flights.rbegin()->empty()) {
281 m_flights.push_back(std::vector<uint16_t>());
282 }
283
284 if(expecting_ccs) {
285 if(!m_messages.empty()) {
286 const uint16_t current_epoch = m_messages.begin()->second.epoch();
287
288 if(m_ccs_epochs.contains(current_epoch)) {
289 return std::make_pair(Handshake_Type::HandshakeCCS, std::vector<uint8_t>());
290 }
291 }
292 return std::make_pair(Handshake_Type::None, std::vector<uint8_t>());
293 }
294
295 auto i = m_messages.find(m_in_message_seq);
296
297 if(i == m_messages.end() || !i->second.complete()) {
298 return std::make_pair(Handshake_Type::None, std::vector<uint8_t>());
299 }
300
301 m_in_message_seq += 1;
302
303 auto result = i->second.message();
304
305 // Free the reassembly buffer for this delivered slot and uncommit its
306 // bytes against the cap. The entry itself stays in m_messages because
307 // the expecting_ccs branch above uses m_messages.begin()->second.epoch()
308 // as an epoch-0 sentinel; it only needs the metadata, not the buffers.
309 BOTAN_ASSERT_NOMSG(m_pending_reassembly_bytes >= i->second.msg_length());
310 m_pending_reassembly_bytes -= i->second.msg_length();
311 i->second.release_buffers();
312
313 return result;
314}

References BOTAN_ASSERT_NOMSG, Botan::TLS::HandshakeCCS, and Botan::TLS::None.

◆ have_more_data()

bool Botan::TLS::Datagram_Handshake_IO::have_more_data ( ) const
overridevirtual

Implements Botan::TLS::Handshake_IO.

Definition at line 179 of file tls_handshake_io.cpp.

179 {
180 return false;
181}

◆ initial_record_version()

Protocol_Version Botan::TLS::Datagram_Handshake_IO::initial_record_version ( ) const
overridevirtual

Implements Botan::TLS::Handshake_IO.

Definition at line 149 of file tls_handshake_io.cpp.

149 {
150 return Protocol_Version::DTLS_V12;
151}

◆ send()

std::vector< uint8_t > Botan::TLS::Datagram_Handshake_IO::send ( const Handshake_Message & msg)
overridevirtual

Implements Botan::TLS::Handshake_IO.

Definition at line 419 of file tls_handshake_io.cpp.

419 {
420 return this->send_under_epoch(msg, m_seqs.current_write_epoch());
421}
std::vector< uint8_t > send_under_epoch(const Handshake_Message &msg, uint16_t epoch) override

References send_under_epoch().

◆ send_under_epoch()

std::vector< uint8_t > Botan::TLS::Datagram_Handshake_IO::send_under_epoch ( const Handshake_Message & msg,
uint16_t epoch )
overridevirtual

Implements Botan::TLS::Handshake_IO.

Definition at line 423 of file tls_handshake_io.cpp.

423 {
424 const std::vector<uint8_t> msg_bits = msg.serialize();
425 const Handshake_Type msg_type = msg.type();
426
427 if(msg_type == Handshake_Type::HandshakeCCS) {
428 m_send_hs(epoch, Record_Type::ChangeCipherSpec, msg_bits);
429 return std::vector<uint8_t>(); // not included in handshake hashes
430 } else if(msg_type == Handshake_Type::HelloVerifyRequest) {
431 // This message is not included in the handshake hashes
432 send_message(m_out_message_seq, epoch, msg_type, msg_bits);
433 m_out_message_seq += 1;
434 return std::vector<uint8_t>();
435 }
436
437 // Note: not saving CCS, instead we know it was there due to change in epoch
438 m_flights.rbegin()->push_back(m_out_message_seq);
439 m_flight_data[m_out_message_seq] = Message_Info(epoch, msg_type, msg_bits);
440
441 m_out_message_seq += 1;
442 m_last_write = steady_clock_ms();
443 m_next_timeout = m_initial_timeout;
444
445 return send_message(m_out_message_seq - 1, epoch, msg_type, msg_bits);
446}

References Botan::TLS::ChangeCipherSpec, Botan::TLS::HandshakeCCS, Botan::TLS::HelloVerifyRequest, Botan::TLS::Handshake_Message::serialize(), and Botan::TLS::Handshake_Message::type().

Referenced by send().

◆ timeout_check()

bool Botan::TLS::Datagram_Handshake_IO::timeout_check ( )
overridevirtual

Implements Botan::TLS::Handshake_IO.

Definition at line 183 of file tls_handshake_io.cpp.

183 {
184 if(m_last_write == 0 || (m_flights.size() > 1 && !m_flights.rbegin()->empty())) {
185 /*
186 If we haven't written anything yet obviously no timeout.
187 Also no timeout possible if we are mid-flight,
188 */
189 return false;
190 }
191
192 const uint64_t ms_since_write = steady_clock_ms() - m_last_write;
193
194 if(ms_since_write < m_next_timeout) {
195 return false;
196 }
197
198 retransmit_last_flight();
199
200 m_next_timeout = std::min(2 * m_next_timeout, m_max_timeout);
201 return true;
202}

The documentation for this class was generated from the following files: