Botan  2.1.0
Crypto and TLS for C++11
tls_channel.cpp
Go to the documentation of this file.
1 /*
2 * TLS Channels
3 * (C) 2011,2012,2014,2015,2016 Jack Lloyd
4 * 2016 Matthias Gierlings
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8 
9 #include <botan/tls_channel.h>
10 #include <botan/tls_messages.h>
11 #include <botan/internal/tls_handshake_state.h>
12 #include <botan/internal/tls_record.h>
13 #include <botan/internal/tls_seq_numbers.h>
14 #include <botan/internal/rounding.h>
15 #include <botan/internal/stl_util.h>
16 #include <botan/loadstor.h>
17 
18 namespace Botan {
19 
20 namespace TLS {
21 
22 size_t TLS::Channel::IO_BUF_DEFAULT_SIZE = 10*1024;
23 
25  Session_Manager& session_manager,
27  const Policy& policy,
28  bool is_datagram,
29  size_t reserved_io_buffer_size) :
30  m_is_datagram(is_datagram),
31  m_callbacks(callbacks),
32  m_session_manager(session_manager),
33  m_policy(policy),
34  m_rng(rng)
35  {
36  init(reserved_io_buffer_size);
37  }
38 
40  data_cb app_data_cb,
42  handshake_cb hs_cb,
43  handshake_msg_cb hs_msg_cb,
44  Session_Manager& session_manager,
46  const Policy& policy,
47  bool is_datagram,
48  size_t io_buf_sz) :
49  m_is_datagram(is_datagram),
50  m_compat_callbacks(new Compat_Callbacks(out, app_data_cb, alert_cb, hs_cb, hs_msg_cb)),
51  m_callbacks(*m_compat_callbacks.get()),
52  m_session_manager(session_manager),
53  m_policy(policy),
54  m_rng(rng)
55  {
56  init(io_buf_sz);
57  }
58 
59 void Channel::init(size_t io_buf_sz)
60  {
61  /* epoch 0 is plaintext, thus null cipher state */
62  m_write_cipher_states[0] = nullptr;
63  m_read_cipher_states[0] = nullptr;
64 
65  m_writebuf.reserve(io_buf_sz);
66  m_readbuf.reserve(io_buf_sz);
67  }
68 
69 void Channel::reset_state()
70  {
71  m_active_state.reset();
72  m_pending_state.reset();
73  m_readbuf.clear();
74  m_write_cipher_states.clear();
75  m_read_cipher_states.clear();
76  }
77 
79  {
80  // So unique_ptr destructors run correctly
81  }
82 
83 Connection_Sequence_Numbers& Channel::sequence_numbers() const
84  {
85  BOTAN_ASSERT(m_sequence_numbers, "Have a sequence numbers object");
86  return *m_sequence_numbers;
87  }
88 
89 std::shared_ptr<Connection_Cipher_State> Channel::read_cipher_state_epoch(uint16_t epoch) const
90  {
91  auto i = m_read_cipher_states.find(epoch);
92  if(i == m_read_cipher_states.end())
93  throw Internal_Error("TLS::Channel No read cipherstate for epoch " + std::to_string(epoch));
94  return i->second;
95  }
96 
97 std::shared_ptr<Connection_Cipher_State> Channel::write_cipher_state_epoch(uint16_t epoch) const
98  {
99  auto i = m_write_cipher_states.find(epoch);
100  if(i == m_write_cipher_states.end())
101  throw Internal_Error("TLS::Channel No write cipherstate for epoch " + std::to_string(epoch));
102  return i->second;
103  }
104 
105 std::vector<X509_Certificate> Channel::peer_cert_chain() const
106  {
107  if(auto active = active_state())
108  return get_peer_cert_chain(*active);
109  return std::vector<X509_Certificate>();
110  }
111 
113  {
114  if(pending_state())
115  throw Internal_Error("create_handshake_state called during handshake");
116 
117  if(auto active = active_state())
118  {
119  Protocol_Version active_version = active->version();
120 
121  if(active_version.is_datagram_protocol() != version.is_datagram_protocol())
122  throw Exception("Active state using version " +
123  active_version.to_string() +
124  " cannot change to " +
125  version.to_string() +
126  " in pending");
127  }
128 
129  if(!m_sequence_numbers)
130  {
131  if(version.is_datagram_protocol())
132  m_sequence_numbers.reset(new Datagram_Sequence_Numbers);
133  else
134  m_sequence_numbers.reset(new Stream_Sequence_Numbers);
135  }
136 
137  using namespace std::placeholders;
138 
139  std::unique_ptr<Handshake_IO> io;
140  if(version.is_datagram_protocol())
141  {
142  io.reset(new Datagram_Handshake_IO(
143  std::bind(&Channel::send_record_under_epoch, this, _1, _2, _3),
144  sequence_numbers(),
145  static_cast<uint16_t>(m_policy.dtls_default_mtu()),
146  m_policy.dtls_initial_timeout(),
147  m_policy.dtls_maximum_timeout()));
148  }
149  else
150  {
151  io.reset(new Stream_Handshake_IO(std::bind(&Channel::send_record, this, _1, _2)));
152  }
153 
154  m_pending_state.reset(new_handshake_state(io.release()));
155 
156  if(auto active = active_state())
157  m_pending_state->set_version(active->version());
158 
159  return *m_pending_state.get();
160  }
161 
163  {
164  if(m_pending_state)
165  return m_pending_state->handshake_io().timeout_check();
166 
167  //FIXME: scan cipher suites and remove epochs older than 2*MSL
168  return false;
169  }
170 
171 void Channel::renegotiate(bool force_full_renegotiation)
172  {
173  if(pending_state()) // currently in handshake?
174  return;
175 
176  if(auto active = active_state())
177  initiate_handshake(create_handshake_state(active->version()),
178  force_full_renegotiation);
179  else
180  throw Exception("Cannot renegotiate on inactive connection");
181  }
182 
184  {
185  auto pending = pending_state();
186 
187  BOTAN_ASSERT(pending && pending->server_hello(),
188  "Have received server hello");
189 
190  if(pending->server_hello()->compression_method() != NO_COMPRESSION)
191  throw Internal_Error("Negotiated unknown compression algorithm");
192 
193  sequence_numbers().new_read_cipher_state();
194 
195  const uint16_t epoch = sequence_numbers().current_read_epoch();
196 
197  BOTAN_ASSERT(m_read_cipher_states.count(epoch) == 0,
198  "No read cipher state currently set for next epoch");
199 
200  // flip side as we are reading
201  std::shared_ptr<Connection_Cipher_State> read_state(
202  new Connection_Cipher_State(pending->version(),
203  (side == CLIENT) ? SERVER : CLIENT,
204  false,
205  pending->ciphersuite(),
206  pending->session_keys(),
207  pending->server_hello()->supports_encrypt_then_mac()));
208 
209  m_read_cipher_states[epoch] = read_state;
210  }
211 
213  {
214  auto pending = pending_state();
215 
216  BOTAN_ASSERT(pending && pending->server_hello(),
217  "Have received server hello");
218 
219  if(pending->server_hello()->compression_method() != NO_COMPRESSION)
220  throw Internal_Error("Negotiated unknown compression algorithm");
221 
222  sequence_numbers().new_write_cipher_state();
223 
224  const uint16_t epoch = sequence_numbers().current_write_epoch();
225 
226  BOTAN_ASSERT(m_write_cipher_states.count(epoch) == 0,
227  "No write cipher state currently set for next epoch");
228 
229  std::shared_ptr<Connection_Cipher_State> write_state(
230  new Connection_Cipher_State(pending->version(),
231  side,
232  true,
233  pending->ciphersuite(),
234  pending->session_keys(),
235  pending->server_hello()->supports_encrypt_then_mac()));
236 
237  m_write_cipher_states[epoch] = write_state;
238  }
239 
240 bool Channel::is_active() const
241  {
242  return (active_state() != nullptr);
243  }
244 
245 bool Channel::is_closed() const
246  {
247  if(active_state() || pending_state())
248  return false;
249 
250  /*
251  * If no active or pending state, then either we had a connection
252  * and it has been closed, or we are a server which has never
253  * received a connection. This case is detectable by also lacking
254  * m_sequence_numbers
255  */
256  return (m_sequence_numbers != nullptr);
257  }
258 
260  {
261  std::swap(m_active_state, m_pending_state);
262  m_pending_state.reset();
263 
264  if(!m_active_state->version().is_datagram_protocol())
265  {
266  // TLS is easy just remove all but the current state
267  const uint16_t current_epoch = sequence_numbers().current_write_epoch();
268 
269  const auto not_current_epoch =
270  [current_epoch](uint16_t epoch) { return (epoch != current_epoch); };
271 
272  map_remove_if(not_current_epoch, m_write_cipher_states);
273  map_remove_if(not_current_epoch, m_read_cipher_states);
274  }
275 
277  }
278 
279 size_t Channel::received_data(const std::vector<uint8_t>& buf)
280  {
281  return this->received_data(buf.data(), buf.size());
282  }
283 
284 size_t Channel::received_data(const uint8_t input[], size_t input_size)
285  {
286  try
287  {
288  while(!is_closed() && input_size)
289  {
290  secure_vector<uint8_t> record_data;
291  uint64_t record_sequence = 0;
292  Record_Type record_type = NO_RECORD;
293  Protocol_Version record_version;
294 
295  size_t consumed = 0;
296 
297  Record_Raw_Input raw_input(input, input_size, consumed, m_is_datagram);
298  Record record(record_data, &record_sequence, &record_version, &record_type);
299  const size_t needed =
300  read_record(m_readbuf,
301  raw_input,
302  record,
303  m_sequence_numbers.get(),
304  std::bind(&TLS::Channel::read_cipher_state_epoch, this,
305  std::placeholders::_1));
306 
307  BOTAN_ASSERT(consumed > 0, "Got to eat something");
308 
309  BOTAN_ASSERT(consumed <= input_size,
310  "Record reader consumed sane amount");
311 
312  input += consumed;
313  input_size -= consumed;
314 
315  BOTAN_ASSERT(input_size == 0 || needed == 0,
316  "Got a full record or consumed all input");
317 
318  if(input_size == 0 && needed != 0)
319  return needed; // need more data to complete record
320 
321  if(record_data.size() > MAX_PLAINTEXT_SIZE)
323  "TLS plaintext record is larger than allowed maximum");
324 
325  if(record_type == HANDSHAKE || record_type == CHANGE_CIPHER_SPEC)
326  {
327  process_handshake_ccs(record_data, record_sequence, record_type, record_version);
328  }
329  else if(record_type == APPLICATION_DATA)
330  {
331  process_application_data(record_sequence, record_data);
332  }
333  else if(record_type == ALERT)
334  {
335  process_alert(record_data);
336  }
337  else if(record_type != NO_RECORD)
338  throw Unexpected_Message("Unexpected record type " +
339  std::to_string(record_type) +
340  " from counterparty");
341  }
342 
343  return 0; // on a record boundary
344  }
345  catch(TLS_Exception& e)
346  {
347  send_fatal_alert(e.type());
348  throw;
349  }
350  catch(Integrity_Failure&)
351  {
353  throw;
354  }
355  catch(Decoding_Error&)
356  {
358  throw;
359  }
360  catch(...)
361  {
363  throw;
364  }
365  }
366 
367 void Channel::process_handshake_ccs(const secure_vector<uint8_t>& record,
368  uint64_t record_sequence,
369  Record_Type record_type,
370  Protocol_Version record_version)
371  {
372  if(!m_pending_state)
373  {
374  // No pending handshake, possibly new:
375  if(record_version.is_datagram_protocol())
376  {
377  if(m_sequence_numbers)
378  {
379  /*
380  * Might be a peer retransmit under epoch - 1 in which
381  * case we must retransmit last flight
382  */
383  sequence_numbers().read_accept(record_sequence);
384 
385  const uint16_t epoch = record_sequence >> 48;
386 
387  if(epoch == sequence_numbers().current_read_epoch())
388  {
389  create_handshake_state(record_version);
390  }
391  else if(epoch == sequence_numbers().current_read_epoch() - 1)
392  {
393  BOTAN_ASSERT(m_active_state, "Have active state here");
394  m_active_state->handshake_io().add_record(unlock(record),
395  record_type,
396  record_sequence);
397  }
398  }
399  else if(record_sequence == 0)
400  {
401  create_handshake_state(record_version);
402  }
403  }
404  else
405  {
406  create_handshake_state(record_version);
407  }
408  }
409 
410  // May have been created in above conditional
411  if(m_pending_state)
412  {
413  m_pending_state->handshake_io().add_record(unlock(record),
414  record_type,
415  record_sequence);
416 
417  while(auto pending = m_pending_state.get())
418  {
419  auto msg = pending->get_next_handshake_msg();
420 
421  if(msg.first == HANDSHAKE_NONE) // no full handshake yet
422  break;
423 
424  process_handshake_msg(active_state(), *pending,
425  msg.first, msg.second);
426  }
427  }
428  }
429 
430 void Channel::process_application_data(uint64_t seq_no, const secure_vector<uint8_t>& record)
431  {
432  if(!active_state())
433  throw Unexpected_Message("Application data before handshake done");
434 
435  /*
436  * OpenSSL among others sends empty records in versions
437  * before TLS v1.1 in order to randomize the IV of the
438  * following record. Avoid spurious callbacks.
439  */
440  if(record.size() > 0)
441  callbacks().tls_record_received(seq_no, record.data(), record.size());
442  }
443 
444 void Channel::process_alert(const secure_vector<uint8_t>& record)
445  {
446  Alert alert_msg(record);
447 
448  if(alert_msg.type() == Alert::NO_RENEGOTIATION)
449  m_pending_state.reset();
450 
451  callbacks().tls_alert(alert_msg);
452 
453  if(alert_msg.is_fatal())
454  {
455  if(auto active = active_state())
456  m_session_manager.remove_entry(active->server_hello()->session_id());
457  }
458 
459  if(alert_msg.type() == Alert::CLOSE_NOTIFY)
460  send_warning_alert(Alert::CLOSE_NOTIFY); // reply in kind
461 
462  if(alert_msg.type() == Alert::CLOSE_NOTIFY || alert_msg.is_fatal())
463  {
464  reset_state();
465  }
466  }
467 
468 
469 void Channel::write_record(Connection_Cipher_State* cipher_state, uint16_t epoch,
470  uint8_t record_type, const uint8_t input[], size_t length)
471  {
472  BOTAN_ASSERT(m_pending_state || m_active_state, "Some connection state exists");
473 
474  Protocol_Version record_version =
475  (m_pending_state) ? (m_pending_state->version()) : (m_active_state->version());
476 
477  Record_Message record_message(record_type, 0, input, length);
478 
479  TLS::write_record(m_writebuf,
480  record_message,
481  record_version,
482  sequence_numbers().next_write_sequence(epoch),
483  cipher_state,
484  m_rng);
485 
486  callbacks().tls_emit_data(m_writebuf.data(), m_writebuf.size());
487  }
488 
489 void Channel::send_record_array(uint16_t epoch, uint8_t type, const uint8_t input[], size_t length)
490  {
491  if(length == 0)
492  return;
493 
494  /*
495  * In versions without an explicit IV field (only TLS v1.0 now that
496  * SSLv3 has been removed) send a single byte record first to randomize
497  * the following (implicit) IV of the following record.
498  *
499  * This isn't needed in TLS v1.1 or higher.
500  *
501  * An empty record also works but apparently some implementations do
502  * not like this (https://bugzilla.mozilla.org/show_bug.cgi?id=665814)
503  *
504  * See http://www.openssl.org/~bodo/tls-cbc.txt for background.
505  */
506 
507  auto cipher_state = write_cipher_state_epoch(epoch);
508 
509  if(type == APPLICATION_DATA && m_active_state->version().supports_explicit_cbc_ivs() == false)
510  {
511  write_record(cipher_state.get(), epoch, type, input, 1);
512  input += 1;
513  length -= 1;
514  }
515 
516  while(length)
517  {
518  const size_t sending = std::min<size_t>(length, MAX_PLAINTEXT_SIZE);
519  write_record(cipher_state.get(), epoch, type, input, sending);
520 
521  input += sending;
522  length -= sending;
523  }
524  }
525 
526 void Channel::send_record(uint8_t record_type, const std::vector<uint8_t>& record)
527  {
528  send_record_array(sequence_numbers().current_write_epoch(),
529  record_type, record.data(), record.size());
530  }
531 
532 void Channel::send_record_under_epoch(uint16_t epoch, uint8_t record_type,
533  const std::vector<uint8_t>& record)
534  {
535  send_record_array(epoch, record_type, record.data(), record.size());
536  }
537 
538 void Channel::send(const uint8_t buf[], size_t buf_size)
539  {
540  if(!is_active())
541  throw Exception("Data cannot be sent on inactive TLS connection");
542 
543  send_record_array(sequence_numbers().current_write_epoch(),
544  APPLICATION_DATA, buf, buf_size);
545  }
546 
547 void Channel::send(const std::string& string)
548  {
549  this->send(reinterpret_cast<const uint8_t*>(string.c_str()), string.size());
550  }
551 
552 void Channel::send_alert(const Alert& alert)
553  {
554  if(alert.is_valid() && !is_closed())
555  {
556  try
557  {
558  send_record(ALERT, alert.serialize());
559  }
560  catch(...) { /* swallow it */ }
561  }
562 
563  if(alert.type() == Alert::NO_RENEGOTIATION)
564  m_pending_state.reset();
565 
566  if(alert.is_fatal())
567  if(auto active = active_state())
568  m_session_manager.remove_entry(active->server_hello()->session_id());
569 
570  if(alert.type() == Alert::CLOSE_NOTIFY || alert.is_fatal())
571  reset_state();
572  }
573 
575  {
576  const bool secure_renegotiation = client_hello->secure_renegotiation();
577 
578  if(auto active = active_state())
579  {
580  const bool active_sr = active->client_hello()->secure_renegotiation();
581 
582  if(active_sr != secure_renegotiation)
584  "Client changed its mind about secure renegotiation");
585  }
586 
587  if(secure_renegotiation)
588  {
589  const std::vector<uint8_t>& data = client_hello->renegotiation_info();
590 
593  "Client sent bad values for secure renegotiation");
594  }
595  }
596 
598  {
599  const bool secure_renegotiation = server_hello->secure_renegotiation();
600 
601  if(auto active = active_state())
602  {
603  const bool active_sr = active->client_hello()->secure_renegotiation();
604 
605  if(active_sr != secure_renegotiation)
607  "Server changed its mind about secure renegotiation");
608  }
609 
610  if(secure_renegotiation)
611  {
612  const std::vector<uint8_t>& data = server_hello->renegotiation_info();
613 
616  "Server sent bad values for secure renegotiation");
617  }
618  }
619 
621  {
622  if(auto active = active_state())
623  return active->client_finished()->verify_data();
624  return std::vector<uint8_t>();
625  }
626 
628  {
629  if(auto active = active_state())
630  {
631  std::vector<uint8_t> buf = active->client_finished()->verify_data();
632  buf += active->server_finished()->verify_data();
633  return buf;
634  }
635 
636  return std::vector<uint8_t>();
637  }
638 
640  {
641  if(auto active = active_state())
642  return active->server_hello()->secure_renegotiation();
643 
644  if(auto pending = pending_state())
645  if(auto hello = pending->server_hello())
646  return hello->secure_renegotiation();
647 
648  return false;
649  }
650 
652  const std::string& context,
653  size_t length) const
654  {
655  if(auto active = active_state())
656  {
657  std::unique_ptr<KDF> prf(active->protocol_specific_prf());
658 
659  const secure_vector<uint8_t>& master_secret =
660  active->session_keys().master_secret();
661 
662  std::vector<uint8_t> salt;
663  salt += active->client_hello()->random();
664  salt += active->server_hello()->random();
665 
666  if(context != "")
667  {
668  size_t context_size = context.length();
669  if(context_size > 0xFFFF)
670  throw Exception("key_material_export context is too long");
671  salt.push_back(get_byte(0, static_cast<uint16_t>(context_size)));
672  salt.push_back(get_byte(1, static_cast<uint16_t>(context_size)));
673  salt += to_byte_vector(context);
674  }
675 
676  return prf->derive_key(length, master_secret, salt, to_byte_vector(label));
677  }
678  else
679  throw Exception("Channel::key_material_export connection not active");
680  }
681 
682 }
683 
684 }
SymmetricKey key_material_export(const std::string &label, const std::string &context, size_t length) const
std::vector< uint8_t > secure_renegotiation_data_for_server_hello() const
virtual std::vector< X509_Certificate > get_peer_cert_chain(const Handshake_State &state) const =0
std::vector< X509_Certificate > peer_cert_chain() const
Callbacks & callbacks() const
Definition: tls_channel.h:241
virtual void remove_entry(const std::vector< uint8_t > &session_id)=0
std::vector< uint8_t > secure_renegotiation_data_for_client_hello() const
std::function< void(Alert, const uint8_t[], size_t)> alert_cb
Definition: tls_channel.h:41
void change_cipher_spec_reader(Connection_Side side)
bool is_valid() const
Definition: tls_alert.h:69
size_t read_record(secure_vector< uint8_t > &readbuf, Record_Raw_Input &raw_input, Record &rec, Connection_Sequence_Numbers *sequence_numbers, get_cipherstate_fn get_cipherstate)
Definition: tls_record.cpp:494
void change_cipher_spec_writer(Connection_Side side)
void send_warning_alert(Alert::Type type)
Definition: tls_channel.h:140
std::function< void(const uint8_t[], size_t)> output_fn
Definition: tls_channel.h:39
std::string to_string() const
Definition: tls_version.cpp:16
virtual void tls_alert(Alert alert)=0
Handshake_State & create_handshake_state(Protocol_Version version)
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
MechanismType type
size_t length() const
Definition: symkey.h:25
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
bool is_closed() const
void send_alert(const Alert &alert)
std::vector< uint8_t > renegotiation_info() const
Definition: tls_messages.h:158
virtual void tls_record_received(uint64_t seq_no, const uint8_t data[], size_t size)=0
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:121
std::function< bool(const Session &)> handshake_cb
Definition: tls_channel.h:42
void send(const uint8_t buf[], size_t buf_size)
bool secure_renegotiation_supported() const
static size_t IO_BUF_DEFAULT_SIZE
Definition: tls_channel.h:44
virtual Handshake_State * new_handshake_state(class Handshake_IO *io)=0
Definition: alg_id.cpp:13
std::vector< uint8_t > to_byte_vector(const std::string &s)
Definition: stl_util.h:20
void send_fatal_alert(Alert::Type type)
Definition: tls_channel.h:145
void secure_renegotiation_check(const Client_Hello *client_hello)
RandomNumberGenerator & m_rng
Definition: ecdh.cpp:52
size_t received_data(const uint8_t buf[], size_t buf_size)
std::function< void(const uint8_t[], size_t)> data_cb
Definition: tls_channel.h:40
virtual void tls_session_activated()
Definition: tls_callbacks.h:92
std::vector< T > unlock(const secure_vector< T > &in)
Definition: secmem.h:125
void map_remove_if(Pred pred, T &assoc)
Definition: stl_util.h:96
Channel(Callbacks &callbacks, Session_Manager &session_manager, RandomNumberGenerator &rng, const Policy &policy, bool is_datagram, size_t io_buf_sz=IO_BUF_DEFAULT_SIZE)
Definition: tls_channel.cpp:24
virtual uint16_t current_write_epoch() const =0
Type type() const
Definition: tls_alert.h:79
virtual void tls_emit_data(const uint8_t data[], size_t size)=0
void renegotiate(bool force_full_renegotiation=false)
void write_record(secure_vector< uint8_t > &output, Record_Message msg, Protocol_Version version, uint64_t seq, Connection_Cipher_State *cs, RandomNumberGenerator &rng)
Definition: tls_record.cpp:213
uint8_t get_byte(size_t byte_num, T input)
Definition: loadstor.h:47
bool secure_renegotiation() const
Definition: tls_messages.h:299
std::vector< uint8_t > renegotiation_info() const
Definition: tls_messages.h:304
virtual void read_accept(uint64_t seq)=0
virtual void process_handshake_msg(const Handshake_State *active_state, Handshake_State &pending_state, Handshake_Type type, const std::vector< uint8_t > &contents)=0
virtual uint16_t current_read_epoch() const =0
Alert::Type type() const
Definition: tls_exceptn.h:24
bool is_fatal() const
Definition: tls_alert.h:74
bool is_datagram_protocol() const
Definition: tls_version.cpp:34
bool secure_renegotiation() const
Definition: tls_messages.h:153
bool is_active() const
std::function< void(const Handshake_Message &)> handshake_msg_cb
Definition: tls_channel.h:43
std::vector< uint8_t > serialize() const
Definition: tls_alert.cpp:31
virtual void initiate_handshake(Handshake_State &state, bool force_full_renegotiation)=0