Botan 3.13.0
Crypto and TLS for C&
Botan::TLS::Client_Impl_12 Class Referencefinal

#include <tls_client_impl_12.h>

Inheritance diagram for Botan::TLS::Client_Impl_12:
Botan::TLS::Channel_Impl_12 Botan::TLS::Channel_Impl

Public Member Functions

std::string application_protocol () const override
 Client_Impl_12 (const std::shared_ptr< Callbacks > &callbacks, const std::shared_ptr< Session_Manager > &session_manager, const std::shared_ptr< Credentials_Manager > &creds, const std::shared_ptr< const Policy > &policy, const std::shared_ptr< RandomNumberGenerator > &rng, Server_Information server_info=Server_Information(), bool datagram=false, const std::vector< std::string > &next_protocols={}, size_t reserved_io_buffer_size=TLS::Channel::IO_BUF_DEFAULT_SIZE)
void close ()
std::optional< std::string > external_psk_identity () const override
size_t from_peer (std::span< const uint8_t > data) override
bool is_active () const override
bool is_closed () const override
bool is_closed_for_reading () const override
bool is_closed_for_writing () const override
bool is_handshake_complete () const override
SymmetricKey key_material_export (std::string_view label, std::string_view context, size_t length) const override
virtual bool new_session_ticket_supported () const
std::optional< std::chrono::milliseconds > next_retransmission_timeout () const override
std::vector< X509_Certificatepeer_cert_chain () const override
std::shared_ptr< const Public_Keypeer_raw_public_key () const override
void renegotiate (bool force_full_renegotiation=false) override
bool secure_renegotiation_supported () const override
void send_alert (const Alert &alert) override
void send_fatal_alert (Alert::Type type)
virtual size_t send_new_session_tickets (const size_t)
void send_warning_alert (Alert::Type type)
bool timeout_check () override
void to_peer (std::span< const uint8_t > data) override
void update_traffic_keys (bool request_peer_update=false) override

Protected Member Functions

void activate_session ()
const std::optional< Active_Connection_State_12 > & active_state () const
Callbackscallbacks () const
void change_cipher_spec_reader (Connection_Side side)
void change_cipher_spec_writer (Connection_Side side)
Handshake_Statecreate_handshake_state (Protocol_Version version, bool epoch0_restart=false)
bool expects_downgrade () const
void inspect_handshake_message (const Handshake_Message &msg)
bool is_downgrading () const
void note_resumption_handle (std::optional< Session_Handle > handle)
const Policypolicy () const
void reset_active_association_state ()
RandomNumberGeneratorrng ()
void secure_renegotiation_check (const Client_Hello_12 *client_hello)
void secure_renegotiation_check (const Server_Hello_12 *server_hello)
std::vector< uint8_t > secure_renegotiation_data_for_client_hello () const
std::vector< uint8_t > secure_renegotiation_data_for_server_hello () const
Session_Managersession_manager ()

Detailed Description

SSL/TLS Client 1.2 implementation

Definition at line 23 of file tls_client_impl_12.h.

Constructor & Destructor Documentation

◆ Client_Impl_12()

Botan::TLS::Client_Impl_12::Client_Impl_12 ( const std::shared_ptr< Callbacks > & callbacks,
const std::shared_ptr< Session_Manager > & session_manager,
const std::shared_ptr< Credentials_Manager > & creds,
const std::shared_ptr< const Policy > & policy,
const std::shared_ptr< RandomNumberGenerator > & rng,
Server_Information server_info = Server_Information(),
bool datagram = false,
const std::vector< std::string > & next_protocols = {},
size_t reserved_io_buffer_size = TLS::Channel::IO_BUF_DEFAULT_SIZE )
explicit

Set up a new TLS client session

Parameters
callbackscontains a set of callback function references required by the TLS client.
session_managermanages session state
credsmanages application/user credentials
policyspecifies other connection policy information
rnga random number generator
server_infois identifying information about the TLS server
datagramspecifies whether to use TLS 1.2 or DTLS 1.2
next_protocolsspecifies protocols to advertise with ALPN
reserved_io_buffer_sizeThis many bytes of memory will be preallocated for the read and write buffers. Smaller values just mean reallocations and copies are more likely.

Definition at line 103 of file tls_client_impl_12.cpp.

111 :
112 Channel_Impl_12(callbacks, session_manager, rng, policy, false, datagram, io_buf_sz),
113 m_creds(creds),
114 m_info(std::move(info)) {
115 BOTAN_ASSERT_NONNULL(m_creds);
116 const auto version = datagram ? Protocol_Version::DTLS_V12 : Protocol_Version::TLS_V12;
117 Handshake_State& state = create_handshake_state(version);
118 send_client_hello(state, false, version, std::nullopt /* no a-priori session to resume */, next_protocols);
119}
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:114
RandomNumberGenerator & rng()
Handshake_State & create_handshake_state(Protocol_Version version, bool epoch0_restart=false)
Session_Manager & session_manager()
const Policy & policy() const
Channel_Impl_12(const std::shared_ptr< Callbacks > &callbacks, const std::shared_ptr< Session_Manager > &session_manager, const std::shared_ptr< RandomNumberGenerator > &rng, const std::shared_ptr< const Policy > &policy, bool is_server, bool is_datagram, size_t io_buf_sz=TLS::Channel::IO_BUF_DEFAULT_SIZE)

References BOTAN_ASSERT_NONNULL, Botan::TLS::Channel_Impl_12::callbacks(), Botan::TLS::Channel_Impl_12::Channel_Impl_12(), Botan::TLS::Channel_Impl_12::create_handshake_state(), Botan::TLS::Channel_Impl_12::policy(), Botan::TLS::Channel_Impl_12::rng(), and Botan::TLS::Channel_Impl_12::session_manager().

Member Function Documentation

◆ activate_session()

void Botan::TLS::Channel_Impl_12::activate_session ( )
protectedinherited

Definition at line 484 of file tls_channel_impl_12.cpp.

484 {
485 BOTAN_ASSERT_NONNULL(m_pending_state);
486
487 const auto& state = *m_pending_state;
488
489 if(!state.version().is_datagram_protocol()) {
490 // TLS is easy just remove all but the current state
491 const uint16_t current_epoch = sequence_numbers().current_write_epoch();
492
493 const auto not_current_epoch = [current_epoch](uint16_t epoch) { return (epoch != current_epoch); };
494
495 map_remove_if(not_current_epoch, m_write_cipher_states);
496 map_remove_if(not_current_epoch, m_read_cipher_states);
497 }
498
499 // RFC 6347 4.2.4: "the node that transmits the last flight (the server in an
500 // ordinary handshake or the client in a resumed handshake) MUST respond to a
501 // retransmit of the peer's last flight with a retransmit of the last
502 // flight." Both endpoints retain handshake sequence state, but only that
503 // node replays its outgoing flight.
504 const bool sent_terminal_dtls_flight = m_is_datagram && (m_is_server == (state.server_hello_done() != nullptr));
505
506 if(m_is_datagram) {
507 m_active_state = Active_Connection_State_12(state, application_protocol(), m_pending_state->take_handshake_io());
508 if(auto* dtls_io = m_active_state->dtls_handshake_io()) {
509 // Retain receive sequence state on both endpoints to distinguish a
510 // retransmission from an unexpected new handshake message. Only the
511 // terminal-flight sender responds by replaying its final flight.
512 dtls_io->finalize_handshake(sent_terminal_dtls_flight);
513 }
514 } else {
515 m_active_state = Active_Connection_State_12(state, application_protocol());
516 }
517
518 clear_pending_handshake_state();
519
521}
virtual void tls_session_activated()
virtual std::string application_protocol() const =0
void map_remove_if(Pred pred, T &assoc)
Definition stl_util.h:54

References Botan::TLS::Channel_Impl::application_protocol(), BOTAN_ASSERT_NONNULL, callbacks(), Botan::map_remove_if(), and Botan::TLS::Callbacks::tls_session_activated().

◆ active_state()

const std::optional< Active_Connection_State_12 > & Botan::TLS::Channel_Impl_12::active_state ( ) const
inlineprotectedinherited

Definition at line 154 of file tls_channel_impl_12.h.

154{ return m_active_state; }

◆ application_protocol()

std::string Botan::TLS::Client_Impl_12::application_protocol ( ) const
inlineoverridevirtual
Returns
network protocol as advertised by the TLS server, if server sent the ALPN extension

Implements Botan::TLS::Channel_Impl.

Definition at line 68 of file tls_client_impl_12.h.

68{ return m_application_protocol; }

◆ callbacks()

Callbacks & Botan::TLS::Channel_Impl_12::callbacks ( ) const
inlineprotectedinherited

◆ change_cipher_spec_reader()

void Botan::TLS::Channel_Impl_12::change_cipher_spec_reader ( Connection_Side side)
protectedinherited

Definition at line 401 of file tls_channel_impl_12.cpp.

401 {
402 const auto* pending = pending_state();
403
404 BOTAN_ASSERT(pending && pending->server_hello(), "Have received server hello");
405
406 if(pending->server_hello()->compression_method() != 0) {
407 throw Internal_Error("Negotiated unknown compression algorithm");
408 }
409
410 sequence_numbers().new_read_cipher_state();
411
412 const uint16_t epoch = sequence_numbers().current_read_epoch();
413
414 BOTAN_ASSERT(!m_read_cipher_states.contains(epoch), "No read cipher state currently set for next epoch");
415
416 // flip side as we are reading
417 auto read_state = std::make_shared<Connection_Cipher_State>(
418 pending->version(),
420 false,
421 pending->ciphersuite(),
422 pending->session_keys(),
423 pending->server_hello()->supports_encrypt_then_mac());
424
425 // The epoch we just left is retained only to absorb reordering, so start its
426 // clock now (see read_cipher_state_epoch). Epoch 0 is the plaintext
427 // placeholder and holds no keys, so the window does not apply to it.
428 if(m_is_datagram && epoch > 1) {
429 if(auto prev = m_read_cipher_states.find(static_cast<uint16_t>(epoch - 1)); prev != m_read_cipher_states.end()) {
430 prev->second.retired_at = callbacks().tls_current_monotonic_clock_ms();
431 }
432 }
433
434 m_read_cipher_states[epoch] = Retained_Read_Cipher_State{.state = read_state, .retired_at = std::nullopt};
435 prune_old_cipher_states(m_read_cipher_states);
436}
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
virtual uint64_t tls_current_monotonic_clock_ms()

References BOTAN_ASSERT, callbacks(), Botan::TLS::Client, Botan::TLS::Server, and Botan::TLS::Callbacks::tls_current_monotonic_clock_ms().

◆ change_cipher_spec_writer()

void Botan::TLS::Channel_Impl_12::change_cipher_spec_writer ( Connection_Side side)
protectedinherited

Definition at line 438 of file tls_channel_impl_12.cpp.

438 {
439 const auto* pending = pending_state();
440
441 BOTAN_ASSERT(pending && pending->server_hello(), "Have received server hello");
442
443 if(pending->server_hello()->compression_method() != 0) {
444 throw Internal_Error("Negotiated unknown compression algorithm");
445 }
446
447 sequence_numbers().new_write_cipher_state();
448
449 const uint16_t epoch = sequence_numbers().current_write_epoch();
450
451 BOTAN_ASSERT(!m_write_cipher_states.contains(epoch), "No write cipher state currently set for next epoch");
452
453 auto write_state = std::make_shared<Connection_Cipher_State>(pending->version(),
454 side,
455 true,
456 pending->ciphersuite(),
457 pending->session_keys(),
458 pending->server_hello()->supports_encrypt_then_mac());
459
460 m_write_cipher_states[epoch] = write_state;
461 prune_old_cipher_states(m_write_cipher_states);
462}

References BOTAN_ASSERT.

◆ close()

void Botan::TLS::Channel_Impl::close ( )
inlineinherited

Send a close notification alert

Definition at line 80 of file tls_channel_impl.h.

80{ send_warning_alert(Alert::CloseNotify); }
void send_warning_alert(Alert::Type type)

References send_warning_alert().

◆ create_handshake_state()

Handshake_State & Botan::TLS::Channel_Impl_12::create_handshake_state ( Protocol_Version version,
bool epoch0_restart = false )
protectedinherited

Definition at line 240 of file tls_channel_impl_12.cpp.

240 {
241 if(pending_state() != nullptr) {
242 throw Internal_Error("create_handshake_state called during handshake");
243 }
244
245 if(m_active_state.has_value()) {
246 const Protocol_Version active_version = m_active_state->version();
247
248 if(active_version.is_datagram_protocol() != version.is_datagram_protocol()) {
249 throw TLS_Exception(Alert::ProtocolVersion,
250 "Active state using version " + active_version.to_string() + " cannot change to " +
251 version.to_string() + " in pending");
252 }
253 }
254
255 if(!m_sequence_numbers) {
256 if(version.is_datagram_protocol()) {
257 m_sequence_numbers = std::make_unique<Datagram_Sequence_Numbers>();
258 } else {
259 m_sequence_numbers = std::make_unique<Stream_Sequence_Numbers>();
260 }
261 }
262
263 // Read epochs at or below this one belong to the association already in place,
264 // so application data under them stays deliverable while this handshake runs.
265 // Anything above it is this handshake's own, unauthenticated until its
266 // Finished. See the application-data gate in from_peer.
267 m_epochs_before_latest_renegotiation = Epochs_Before_Latest_Renegotiation{sequence_numbers().current_read_epoch(),
268 sequence_numbers().current_write_epoch()};
269
270 // Floor for the pending handshake's reassembly: a delayed record from the
271 // handshake arrives under a lower epoch and must be rejected. It would
272 // otherwise take the sequence slot the real message needs.
273 //
274 // Zero on an epoch-zero restart, because there the peer legitimately
275 // begins again at epoch zero and the floor would reject it. This is keyed
276 // on the restart actually occurring, not on the policy allowing it: an
277 // ordinary renegotiation needs the floor either way.
278 const uint16_t initial_epoch = epoch0_restart ? 0 : m_epochs_before_latest_renegotiation->read_epoch;
279
280 using namespace std::placeholders;
281
282 std::unique_ptr<Handshake_IO> io;
283 if(version.is_datagram_protocol()) {
284 const uint16_t mtu = static_cast<uint16_t>(policy().dtls_default_mtu());
285 const size_t initial_timeout_ms = policy().dtls_initial_timeout();
286 const size_t max_timeout_ms = policy().dtls_maximum_timeout();
287 const std::optional<size_t> max_retransmissions = policy().dtls_maximum_retransmissions();
288
289 auto send_record_f = [this](uint16_t epoch, Record_Type record_type, const std::vector<uint8_t>& record) {
290 send_record_under_epoch(epoch, record_type, record);
291 };
292 auto clock_f = [this]() { return callbacks().tls_current_monotonic_clock_ms(); };
293 io = std::make_unique<Datagram_Handshake_IO>(send_record_f,
294 clock_f,
295 sequence_numbers(),
296 mtu,
297 initial_timeout_ms,
298 max_timeout_ms,
299 max_retransmissions,
300 policy().maximum_handshake_message_size(),
301 initial_epoch);
302 } else {
303 auto send_record_f = [this](Record_Type rec_type, const std::vector<uint8_t>& record) {
304 send_record(rec_type, record);
305 };
306 io = std::make_unique<Stream_Handshake_IO>(send_record_f);
307 }
308
309 m_pending_state = new_handshake_state(std::move(io));
310
311 if(m_active_state.has_value()) {
312 m_pending_state->set_version(m_active_state->version());
313 }
314
315 return *m_pending_state;
316}
virtual std::unique_ptr< Handshake_State > new_handshake_state(std::unique_ptr< Handshake_IO > io)=0
virtual size_t dtls_maximum_timeout() const
virtual size_t dtls_default_mtu() const
virtual std::optional< size_t > dtls_maximum_retransmissions() const
virtual size_t dtls_initial_timeout() const

References callbacks(), Botan::TLS::Policy::dtls_default_mtu(), Botan::TLS::Policy::dtls_initial_timeout(), Botan::TLS::Policy::dtls_maximum_retransmissions(), Botan::TLS::Policy::dtls_maximum_timeout(), Botan::TLS::Protocol_Version::is_datagram_protocol(), new_handshake_state(), policy(), Botan::TLS::Callbacks::tls_current_monotonic_clock_ms(), and Botan::TLS::Protocol_Version::to_string().

Referenced by Botan::TLS::Client_Impl_12::Client_Impl_12(), and renegotiate().

◆ expects_downgrade()

bool Botan::TLS::Channel_Impl::expects_downgrade ( ) const
inlineprotectedinherited

Definition at line 290 of file tls_channel_impl.h.

290 {
291#if defined(BOTAN_HAS_TLS_DOWNGRADE_SUPPORT)
292 return m_downgrade_info != nullptr;
293#else
294 return false;
295#endif
296 }

Referenced by Botan::TLS::Client_Impl_13::Client_Impl_13(), and Botan::TLS::Channel_Impl_13::from_peer().

◆ external_psk_identity()

std::optional< std::string > Botan::TLS::Channel_Impl_12::external_psk_identity ( ) const
overridevirtualinherited
Returns
identity of the PSK used for this connection or std::nullopt if no PSK was used.

Implements Botan::TLS::Channel_Impl.

Definition at line 230 of file tls_channel_impl_12.cpp.

230 {
231 if(m_active_state.has_value()) {
232 return m_active_state->psk_identity();
233 }
234 if(const auto* state = pending_state()) {
235 return state->psk_identity();
236 }
237 return std::nullopt;
238}

◆ from_peer()

size_t Botan::TLS::Channel_Impl_12::from_peer ( std::span< const uint8_t > data)
overridevirtualinherited

Inject TLS traffic received from counterparty

Returns
a hint as the how many more bytes we need to q the current record (this may be 0 if on a record boundary)

Implements Botan::TLS::Channel_Impl.

Definition at line 523 of file tls_channel_impl_12.cpp.

523 {
524 const bool allow_epoch0_restart = m_is_datagram && m_is_server && policy().allow_dtls_epoch0_restart();
525
526 const auto* input = data.data();
527 auto input_size = data.size();
528
529 try {
530 while(input_size > 0) {
531 // A fatal alert destroys the cipher states, so nothing further can even
532 // be decrypted. Closure by close_notify is different: the responding
533 // close_notify still has to be read, so those records keep flowing
534 // through the loop and are filtered per record type below.
535 if(m_had_fatal_alert) {
536 return 0;
537 }
538
539 size_t consumed = 0;
540
541 auto get_epoch = [this](uint16_t epoch) { return read_cipher_state_epoch(epoch); };
542
543 const Record_Header record = read_record(m_is_datagram,
544 m_readbuf,
545 input,
546 input_size,
547 consumed,
548 m_record_buf,
549 m_sequence_numbers.get(),
550 get_epoch,
551 allow_epoch0_restart);
552
553 const size_t needed = record.needed();
554
555 BOTAN_ASSERT(consumed > 0, "Got to eat something");
556
557 BOTAN_ASSERT(consumed <= input_size, "Record reader consumed sane amount");
558
559 input += consumed;
560 input_size -= consumed;
561
562 BOTAN_ASSERT(input_size == 0 || needed == 0, "Got a full record or consumed all input");
563
564 if(input_size == 0 && needed != 0) {
565 return needed; // need more data to complete record
566 }
567
568 // Ignore invalid records in DTLS
569 if(m_is_datagram && record.type() == Record_Type::Invalid) {
570 return 0;
571 }
572
573 const bool old_unprotected_record = m_is_datagram && record.epoch() == 0 && m_active_state.has_value() &&
574 sequence_numbers().current_read_epoch() > 0;
575
576 // Once encrypted traffic is expected, epoch-zero records are
577 // unauthenticated. Only handshake records can be useful as part of a
578 // retransmitted flight or an explicitly allowed association restart.
579 if(old_unprotected_record && record.type() != Record_Type::Handshake &&
580 record.type() != Record_Type::ChangeCipherSpec) {
581 continue;
582 }
583
584 if(m_record_buf.size() > MAX_PLAINTEXT_SIZE) {
585 if(old_unprotected_record) {
586 continue;
587 }
588
589 throw TLS_Exception(Alert::RecordOverflow, "TLS plaintext record is larger than allowed maximum");
590 }
591
592 const bool epoch0_restart = allow_epoch0_restart && record.epoch() == 0 && m_active_state.has_value();
593 BOTAN_ASSERT_IMPLICATION(epoch0_restart, allow_epoch0_restart, "Allowed state");
594
595 const bool initial_record = epoch0_restart || (pending_state() == nullptr && !m_active_state.has_value());
596 bool initial_handshake_message = false;
597 if(record.type() == Record_Type::Handshake && !m_record_buf.empty()) {
598 const Handshake_Type type = static_cast<Handshake_Type>(m_record_buf[0]);
599 initial_handshake_message = (type == Handshake_Type::ClientHello);
600 }
601
602 if(record.type() != Record_Type::Alert && !old_unprotected_record) {
603 if(initial_record) {
604 // For initial records just check for basic sanity
605 if(record.version().major_version() != 3 && record.version().major_version() != 0xFE) {
606 throw TLS_Exception(Alert::ProtocolVersion, "Received unexpected record version in initial record");
607 }
608 } else if(const auto* pending = pending_state()) {
609 if(pending->server_hello() != nullptr && !initial_handshake_message &&
610 record.version() != pending->version()) {
611 throw TLS_Exception(Alert::ProtocolVersion, "Received unexpected record version");
612 }
613 } else if(m_active_state.has_value()) {
614 if(record.version() != m_active_state->version() && !initial_handshake_message) {
615 throw TLS_Exception(Alert::ProtocolVersion, "Received unexpected record version");
616 }
617 }
618 }
619
620 // RFC 5246 7.2.1: "Any data received after a closure alert is ignored."
621 // This is about a closure alert the peer sent us. A peer that keeps
622 // talking after *our* close_notify is a different case, kept as an
623 // error below; BoGo's Shutdown-Shim-ApplicationData requires it.
624 if(m_peer_closed_connection && record.type() != Record_Type::Alert) {
625 continue;
626 }
627
628 if(record.type() == Record_Type::Handshake || record.type() == Record_Type::ChangeCipherSpec) {
629 if(m_has_been_closed) {
630 throw TLS_Exception(Alert::UnexpectedMessage, "Received handshake data after connection closure");
631 }
632 process_handshake_ccs(m_record_buf, record.sequence(), record.type(), record.version(), epoch0_restart);
633 } else if(record.type() == Record_Type::ApplicationData) {
634 if(m_has_been_closed) {
635 throw TLS_Exception(Alert::UnexpectedMessage, "Received application data after connection closure");
636 }
637 if(pending_state() != nullptr) {
638 /*
639 What matters is which epoch the record belongs to, not which role we
640 are playing.
641
642 RFC 6347 4.2.4: "Implementations MUST either discard or buffer all
643 application data packets for the new epoch until they have received
644 the Finished message for that epoch." Data under the epoch this
645 handshake installed is not authenticated until its Finished, so it
646 must not reach the application; equally it is not an error, because
647 ordinary reordering produces it whenever a peer writes immediately
648 after activating.
649
650 Data under an epoch the established association owns stays valid
651 while a renegotiation is in flight, per 4.1.
652
653 Epoch zero is neither: application data there is plaintext, so it is
654 never legitimate and no association is at stake.
655 */
656 if(m_is_datagram && record.epoch() > 0) {
657 const uint16_t active_epoch =
658 m_epochs_before_latest_renegotiation ? m_epochs_before_latest_renegotiation->read_epoch : 0;
659
660 if(!m_active_state.has_value() || record.epoch() > active_epoch) {
661 continue; // this handshake's epoch, still unauthenticated
662 }
663 } else {
664 throw TLS_Exception(Alert::UnexpectedMessage, "Can't interleave application and handshake data");
665 }
666 }
667 process_application_data(record.sequence(), m_record_buf);
668 } else if(record.type() == Record_Type::Alert) {
669 process_alert(m_record_buf);
670 } else if(record.type() != Record_Type::Invalid) {
671 throw Unexpected_Message("Unexpected record type " + std::to_string(static_cast<size_t>(record.type())) +
672 " from counterparty");
673 }
674 }
675
676 return 0; // on a record boundary
677 } catch(TLS_Exception& e) {
678 send_fatal_alert(e.type());
679 throw;
680 } catch(Invalid_Authentication_Tag&) {
681 send_fatal_alert(Alert::BadRecordMac);
682 throw;
683 } catch(Decoding_Error&) {
684 send_fatal_alert(Alert::DecodeError);
685 throw;
686 } catch(...) {
687 send_fatal_alert(Alert::InternalError);
688 throw;
689 }
690}
#define BOTAN_ASSERT_IMPLICATION(expr1, expr2, msg)
Definition assert.h:101
void send_fatal_alert(Alert::Type type)
virtual bool allow_dtls_epoch0_restart() const
Record_Header read_record(bool is_datagram, secure_vector< uint8_t > &readbuf, const uint8_t input[], size_t input_len, size_t &consumed, secure_vector< uint8_t > &recbuf, Connection_Sequence_Numbers *sequence_numbers, const get_cipherstate_fn &get_cipherstate, bool allow_epoch0_restart)
@ MAX_PLAINTEXT_SIZE
Definition tls_magic.h:35

References Botan::TLS::Alert, Botan::TLS::Policy::allow_dtls_epoch0_restart(), Botan::TLS::ApplicationData, BOTAN_ASSERT, BOTAN_ASSERT_IMPLICATION, Botan::TLS::ChangeCipherSpec, Botan::TLS::ClientHello, Botan::TLS::Record_Header::epoch(), Botan::TLS::Handshake, Botan::TLS::Invalid, Botan::TLS::Protocol_Version::major_version(), Botan::TLS::MAX_PLAINTEXT_SIZE, Botan::TLS::Record_Header::needed(), policy(), Botan::TLS::read_record(), Botan::TLS::Channel_Impl::send_fatal_alert(), Botan::TLS::Record_Header::sequence(), Botan::TLS::Record_Header::type(), Botan::TLS::TLS_Exception::type(), and Botan::TLS::Record_Header::version().

◆ inspect_handshake_message()

void Botan::TLS::Channel_Impl_12::inspect_handshake_message ( const Handshake_Message & msg)
protectedinherited

◆ is_active()

bool Botan::TLS::Channel_Impl_12::is_active ( ) const
overridevirtualinherited
Returns
true iff the connection is active for sending application data

Implements Botan::TLS::Channel_Impl.

Definition at line 468 of file tls_channel_impl_12.cpp.

468 {
469 return !is_closed() && is_handshake_complete();
470}
bool is_handshake_complete() const override

References is_closed(), and is_handshake_complete().

Referenced by to_peer().

◆ is_closed()

bool Botan::TLS::Channel_Impl_12::is_closed ( ) const
overridevirtualinherited
Returns
true iff the connection has been definitely closed

Implements Botan::TLS::Channel_Impl.

Definition at line 480 of file tls_channel_impl_12.cpp.

480 {
481 return m_has_been_closed;
482}

Referenced by is_active(), is_closed_for_reading(), is_closed_for_writing(), and send_alert().

◆ is_closed_for_reading()

bool Botan::TLS::Channel_Impl_12::is_closed_for_reading ( ) const
inlineoverridevirtualinherited
Returns
true iff the connection is active for sending application data

Implements Botan::TLS::Channel_Impl.

Definition at line 98 of file tls_channel_impl_12.h.

98{ return is_closed(); }

References is_closed().

◆ is_closed_for_writing()

bool Botan::TLS::Channel_Impl_12::is_closed_for_writing ( ) const
inlineoverridevirtualinherited
Returns
true iff the connection has been definitely closed

Implements Botan::TLS::Channel_Impl.

Definition at line 100 of file tls_channel_impl_12.h.

100{ return is_closed(); }

References is_closed().

◆ is_downgrading()

bool Botan::TLS::Channel_Impl::is_downgrading ( ) const
inlineprotectedinherited

Indicates whether a downgrade to TLS 1.2 or lower is in progress

See also
Downgrade_Information

Definition at line 282 of file tls_channel_impl.h.

282 {
283#if defined(BOTAN_HAS_TLS_DOWNGRADE_SUPPORT)
284 return m_downgrade_info && m_downgrade_info->will_downgrade;
285#else
286 return false;
287#endif
288 }

Referenced by Botan::TLS::Channel_Impl_13::from_peer(), Botan::TLS::Channel_Impl_13::key_material_export(), and Botan::TLS::Channel_Impl_13::update_traffic_keys().

◆ is_handshake_complete()

bool Botan::TLS::Channel_Impl_12::is_handshake_complete ( ) const
overridevirtualinherited
Returns
true iff the TLS handshake completed successfully

Implements Botan::TLS::Channel_Impl.

Definition at line 464 of file tls_channel_impl_12.cpp.

464 {
465 return m_active_state.has_value();
466}

Referenced by is_active().

◆ key_material_export()

SymmetricKey Botan::TLS::Channel_Impl_12::key_material_export ( std::string_view label,
std::string_view context,
size_t length ) const
overridevirtualinherited

Key material export (RFC 5705)

Parameters
labela disambiguating label string
contexta per-association context value
lengththe length of the desired key in bytes
Returns
key of length bytes

Implements Botan::TLS::Channel_Impl.

Definition at line 1022 of file tls_channel_impl_12.cpp.

1024 {
1025 if(!m_active_state.has_value()) {
1026 throw Invalid_State("Channel_Impl_12::key_material_export connection not active");
1027 }
1028
1029 // A fatal alert should have already cleared the active state:
1030 BOTAN_ASSERT_NOMSG(!m_had_fatal_alert);
1031
1032 if(pending_state() != nullptr) {
1033 throw Invalid_State("Channel_Impl_12::key_material_export cannot export during renegotiation");
1034 }
1035
1036 auto prf = callbacks().tls12_protocol_specific_kdf(m_active_state->prf_algo());
1037
1038 const auto salt = [&] {
1039 if(context.empty()) {
1040 return concat(m_active_state->client_random(), m_active_state->server_random());
1041 } else {
1042 return concat(m_active_state->client_random(),
1043 m_active_state->server_random(),
1044 store_be(static_cast<uint16_t>(context.size())),
1045 as_span_of_bytes(context));
1046 }
1047 }();
1048
1049 return SymmetricKey(prf->derive_key(length, m_active_state->master_secret(), salt, as_span_of_bytes(label)));
1050}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
virtual std::unique_ptr< KDF > tls12_protocol_specific_kdf(std::string_view prf_algo) const
OctetString SymmetricKey
Definition symkey.h:153
std::span< const uint8_t > as_span_of_bytes(const char *s, size_t len)
Definition mem_utils.h:59
constexpr auto concat(Rs &&... ranges)
Definition concat_util.h:90
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:745

References Botan::as_span_of_bytes(), BOTAN_ASSERT_NOMSG, callbacks(), Botan::concat(), Botan::store_be(), and Botan::TLS::Callbacks::tls12_protocol_specific_kdf().

◆ new_session_ticket_supported()

virtual bool Botan::TLS::Channel_Impl::new_session_ticket_supported ( ) const
inlinevirtualinherited
Returns
true if this channel can issue TLS 1.3 style session tickets.

Reimplemented in Botan::TLS::Server_Impl_13.

Definition at line 146 of file tls_channel_impl.h.

146{ return false; }

◆ next_retransmission_timeout()

std::optional< std::chrono::milliseconds > Botan::TLS::Channel_Impl_12::next_retransmission_timeout ( ) const
overridevirtualinherited

Reimplemented from Botan::TLS::Channel_Impl.

Definition at line 472 of file tls_channel_impl_12.cpp.

472 {
473 if(m_is_datagram && !m_has_been_closed && m_pending_state) {
474 return m_pending_state->handshake_io().next_retransmission_timeout();
475 }
476
477 return std::nullopt;
478}

◆ note_resumption_handle()

void Botan::TLS::Channel_Impl_12::note_resumption_handle ( std::optional< Session_Handle > handle)
protectedinherited

Record the resumption handle this connection was established or resumed under, so that a fatal alert can invalidate it. The ServerHello session ID does not identify a ticket-backed session.

Definition at line 127 of file tls_channel_impl_12.cpp.

127 {
128 m_resumption_handle = std::move(handle);
129}

◆ peer_cert_chain()

std::vector< X509_Certificate > Botan::TLS::Channel_Impl_12::peer_cert_chain ( ) const
overridevirtualinherited
Returns
certificate chain of the peer (may be empty)

Implements Botan::TLS::Channel_Impl.

Definition at line 223 of file tls_channel_impl_12.cpp.

223 {
224 if(m_active_state.has_value()) {
225 return m_active_state->peer_certs();
226 }
227 return std::vector<X509_Certificate>();
228}

◆ peer_raw_public_key()

std::shared_ptr< const Public_Key > Botan::TLS::Channel_Impl_12::peer_raw_public_key ( ) const
inlineoverridevirtualinherited

Note: Raw public key for authentication (RFC7250) is currently not implemented for TLS 1.2.

Returns
raw public key of the peer (will be nullptr)

Implements Botan::TLS::Channel_Impl.

Definition at line 113 of file tls_channel_impl_12.h.

113{ return nullptr; }

◆ policy()

const Policy & Botan::TLS::Channel_Impl_12::policy ( ) const
inlineprotectedinherited

◆ renegotiate()

void Botan::TLS::Channel_Impl_12::renegotiate ( bool force_full_renegotiation = false)
overridevirtualinherited

Attempt to renegotiate the session

Parameters
force_full_renegotiationif true, require a full renegotiation, otherwise allow session resumption

Implements Botan::TLS::Channel_Impl.

Definition at line 373 of file tls_channel_impl_12.cpp.

373 {
374 if(pending_state() != nullptr) { // currently in handshake?
375 return;
376 }
377
378 if(m_active_state.has_value()) {
379 // A DTLS handshake consumes one read and one write epoch. Refuse here if
380 // either is spent, so the caller learns before the handshake tears the
381 // working association down partway through. See next_epoch().
382 if(m_is_datagram &&
383 (sequence_numbers().current_read_epoch() == 0xFFFF || sequence_numbers().current_write_epoch() == 0xFFFF)) {
384 throw Invalid_State("DTLS epoch counter exhausted, a new association is required");
385 }
386
387 if(!force_full_renegotiation) {
388 force_full_renegotiation = !policy().allow_resumption_for_renegotiation();
389 }
390
391 initiate_handshake(create_handshake_state(m_active_state->version()), force_full_renegotiation);
392 } else {
393 throw Invalid_State("Cannot renegotiate on inactive connection");
394 }
395}
virtual void initiate_handshake(Handshake_State &state, bool force_full_renegotiation)=0
virtual bool allow_resumption_for_renegotiation() const

References Botan::TLS::Policy::allow_resumption_for_renegotiation(), create_handshake_state(), initiate_handshake(), and policy().

◆ reset_active_association_state()

void Botan::TLS::Channel_Impl_12::reset_active_association_state ( )
protectedinherited

Definition at line 169 of file tls_channel_impl_12.cpp.

169 {
170 // This operation only makes sense for DTLS
171 BOTAN_ASSERT_NOMSG(m_is_datagram);
172 m_active_state.reset();
173 m_read_cipher_states.clear();
174 m_write_cipher_states.clear();
175
176 m_write_cipher_states[0] = nullptr;
177 m_read_cipher_states[0] = {};
178
179 if(m_sequence_numbers) {
180 m_sequence_numbers->reset(); // NOLINT(*-ambiguous-smartptr-reset-call)
181 }
182}

References BOTAN_ASSERT_NOMSG.

◆ rng()

RandomNumberGenerator & Botan::TLS::Channel_Impl_12::rng ( )
inlineprotectedinherited

◆ secure_renegotiation_check() [1/2]

void Botan::TLS::Channel_Impl_12::secure_renegotiation_check ( const Client_Hello_12 * client_hello)
protectedinherited

Definition at line 957 of file tls_channel_impl_12.cpp.

957 {
958 BOTAN_ASSERT_NONNULL(client_hello);
959 const bool secure_renegotiation = client_hello->secure_renegotiation();
960
961 if(m_active_state && m_active_state->client_supports_secure_renegotiation() != secure_renegotiation) {
962 throw TLS_Exception(Alert::HandshakeFailure, "Client changed its mind about secure renegotiation");
963 }
964
965 if(secure_renegotiation) {
966 const std::vector<uint8_t>& data = client_hello->renegotiation_info();
967
968 const auto expected = secure_renegotiation_data_for_client_hello();
969 if(!CT::is_equal<uint8_t>(data, expected).as_bool()) {
970 throw TLS_Exception(Alert::HandshakeFailure, "Client sent bad values for secure renegotiation");
971 }
972 }
973}
std::vector< uint8_t > secure_renegotiation_data_for_client_hello() const
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:798

References BOTAN_ASSERT_NONNULL, Botan::CT::is_equal(), Botan::TLS::Client_Hello_12::renegotiation_info(), Botan::TLS::Client_Hello_12::secure_renegotiation(), and secure_renegotiation_data_for_client_hello().

◆ secure_renegotiation_check() [2/2]

void Botan::TLS::Channel_Impl_12::secure_renegotiation_check ( const Server_Hello_12 * server_hello)
protectedinherited

Definition at line 975 of file tls_channel_impl_12.cpp.

975 {
976 BOTAN_ASSERT_NONNULL(server_hello);
977 const bool secure_renegotiation = server_hello->secure_renegotiation();
978
979 if(m_active_state && m_active_state->server_supports_secure_renegotiation() != secure_renegotiation) {
980 throw TLS_Exception(Alert::HandshakeFailure, "Server changed its mind about secure renegotiation");
981 }
982
983 if(secure_renegotiation) {
984 const std::vector<uint8_t>& data = server_hello->renegotiation_info();
985
986 const auto expected = secure_renegotiation_data_for_server_hello();
987 if(!CT::is_equal<uint8_t>(data, expected).as_bool()) {
988 throw TLS_Exception(Alert::HandshakeFailure, "Server sent bad values for secure renegotiation");
989 }
990 }
991}
std::vector< uint8_t > secure_renegotiation_data_for_server_hello() const

References BOTAN_ASSERT_NONNULL, Botan::CT::is_equal(), Botan::TLS::Server_Hello_12::renegotiation_info(), Botan::TLS::Server_Hello_12::secure_renegotiation(), and secure_renegotiation_data_for_server_hello().

◆ secure_renegotiation_data_for_client_hello()

std::vector< uint8_t > Botan::TLS::Channel_Impl_12::secure_renegotiation_data_for_client_hello ( ) const
protectedinherited

Definition at line 993 of file tls_channel_impl_12.cpp.

993 {
994 if(m_active_state.has_value()) {
995 return m_active_state->client_finished_verify_data();
996 }
997 return std::vector<uint8_t>();
998}

Referenced by secure_renegotiation_check().

◆ secure_renegotiation_data_for_server_hello()

std::vector< uint8_t > Botan::TLS::Channel_Impl_12::secure_renegotiation_data_for_server_hello ( ) const
protectedinherited

Definition at line 1000 of file tls_channel_impl_12.cpp.

1000 {
1001 if(m_active_state.has_value()) {
1002 return concat(m_active_state->client_finished_verify_data(), m_active_state->server_finished_verify_data());
1003 } else {
1004 return {};
1005 }
1006}

References Botan::concat().

Referenced by secure_renegotiation_check().

◆ secure_renegotiation_supported()

bool Botan::TLS::Channel_Impl_12::secure_renegotiation_supported ( ) const
overridevirtualinherited
Returns
true iff the counterparty supports the secure renegotiation extensions.

Implements Botan::TLS::Channel_Impl.

Definition at line 1008 of file tls_channel_impl_12.cpp.

1008 {
1009 if(m_active_state.has_value()) {
1010 return m_active_state->server_supports_secure_renegotiation();
1011 }
1012
1013 if(const auto* pending = pending_state()) {
1014 if(const auto* hello = pending->server_hello()) {
1015 return hello->secure_renegotiation();
1016 }
1017 }
1018
1019 return false;
1020}

◆ send_alert()

void Botan::TLS::Channel_Impl_12::send_alert ( const Alert & alert)
overridevirtualinherited

Send a TLS alert message. If the alert is fatal, the internal state (keys, etc) will be reset.

Parameters
alertthe Alert to send

Implements Botan::TLS::Channel_Impl.

Definition at line 908 of file tls_channel_impl_12.cpp.

908 {
909 const bool ready_to_send_anything = !is_closed() && m_sequence_numbers;
910 if(alert.is_valid() && ready_to_send_anything) {
911 try {
912 send_record(Record_Type::Alert, alert.serialize());
913 } catch(...) { /* swallow it */
914 }
915 }
916
917 // RFC 5246 7.2.2:
918 // no_renegotiation
919 // Sent by the client in response to a hello request or by the
920 // server in response to a client hello after initial handshaking.
921 //
922 // In this case we are the peer sending the refusal, so there is no reason
923 // for our epochs to have moved. If they somehow did, clear the pending
924 // state. A strictly better approach here would be to simply throw
925 // Internal_Error, but send_alert is called from within catch handlers
926 // so this is not currently viable.
927 if(alert.type() == Alert::NoRenegotiation && m_active_state.has_value()) {
928 if(pending_handshake_epochs_unmoved()) {
929 clear_pending_handshake_state();
930 }
931 }
932
933 if(alert.is_fatal()) {
934 // Order matters: the channel is made unusable and its secrets destroyed
935 // before any application-supplied storage is touched, so a throwing
936 // session manager cannot leave is_active() true with live keys.
937 m_had_fatal_alert = true;
938 m_has_been_closed = true;
939
940 // Alert::None is the local teardown that is never sent to the peer, used
941 // where the trigger was unauthenticated input or a local timeout. Evicting
942 // the resumption state on that basis would hand anyone able to reach the
943 // address the ability to destroy it, which is what keeping the teardown
944 // local exists to prevent.
945 const auto invalidated =
946 (alert.type() == Alert::None) ? std::vector<Session_Handle>() : take_sessions_to_invalidate();
947
948 reset_state();
949 invalidate_sessions(invalidated);
950 }
951
952 if(alert.type() == Alert::CloseNotify || alert.is_fatal()) {
953 m_has_been_closed = true;
954 }
955}

References Botan::TLS::Alert, is_closed(), Botan::TLS::Alert::is_fatal(), Botan::TLS::Alert::is_valid(), Botan::TLS::Alert::serialize(), and Botan::TLS::Alert::type().

◆ send_fatal_alert()

void Botan::TLS::Channel_Impl::send_fatal_alert ( Alert::Type type)
inlineinherited

Send a fatal alert

Definition at line 75 of file tls_channel_impl.h.

75{ send_alert(Alert(type, true)); }
virtual void send_alert(const Alert &alert)=0

References Botan::TLS::Alert, and send_alert().

Referenced by Botan::TLS::Channel_Impl_12::from_peer(), and Botan::TLS::Channel_Impl_13::from_peer().

◆ send_new_session_tickets()

virtual size_t Botan::TLS::Channel_Impl::send_new_session_tickets ( const size_t )
inlinevirtualinherited

Send tickets new session tickets to the peer. This is only supported on TLS 1.3 servers.

If the server's Session_Manager does not accept the generated Session objects, the server implementation won't be able to send new tickets. Additionally, anything but TLS 1.3 servers will return 0 (because they don't support sending such session tickets).

Returns
the number of session tickets successfully sent to the client

Reimplemented in Botan::TLS::Server_Impl_13.

Definition at line 159 of file tls_channel_impl.h.

159{ return 0; }

◆ send_warning_alert()

void Botan::TLS::Channel_Impl::send_warning_alert ( Alert::Type type)
inlineinherited

Send a warning alert

Definition at line 70 of file tls_channel_impl.h.

70{ send_alert(Alert(type, false)); }

References Botan::TLS::Alert, and send_alert().

Referenced by close().

◆ session_manager()

Session_Manager & Botan::TLS::Channel_Impl_12::session_manager ( )
inlineprotectedinherited

Definition at line 182 of file tls_channel_impl_12.h.

182{ return *m_session_manager; }

Referenced by Channel_Impl_12(), Botan::TLS::Client_Impl_12::Client_Impl_12(), and Botan::TLS::Server_Impl_12::Server_Impl_12().

◆ timeout_check()

bool Botan::TLS::Channel_Impl_12::timeout_check ( )
overridevirtualinherited

Perform a handshake timeout check. This does nothing unless this is a DTLS channel with a handshake in progress.

Implements Botan::TLS::Channel_Impl.

Definition at line 358 of file tls_channel_impl_12.cpp.

358 {
359 if(m_is_datagram && !m_has_been_closed && m_pending_state) {
360 try {
361 return m_pending_state->handshake_io().timeout_check();
362 } catch(const TLS_Exception&) {
363 abandon_timed_out_handshake();
364 throw;
365 }
366 }
367
368 // Old cipher states are pruned at install time (see prune_old_cipher_states),
369 // so no periodic cleanup is needed here.
370 return false;
371}

◆ to_peer()

void Botan::TLS::Channel_Impl_12::to_peer ( std::span< const uint8_t > data)
overridevirtualinherited

Inject plaintext intended for counterparty Throws an exception if is_active() is false

Implements Botan::TLS::Channel_Impl.

Definition at line 900 of file tls_channel_impl_12.cpp.

900 {
901 if(!is_active()) {
902 throw Invalid_State("Data cannot be sent on inactive TLS connection");
903 }
904
905 send_record_array(sequence_numbers().current_write_epoch(), Record_Type::ApplicationData, data.data(), data.size());
906}

References Botan::TLS::ApplicationData, and is_active().

◆ update_traffic_keys()

void Botan::TLS::Channel_Impl_12::update_traffic_keys ( bool request_peer_update = false)
overridevirtualinherited

Attempt to update the session's traffic key material Note that this is possible with a TLS 1.3 channel, only.

Parameters
request_peer_updateif true, require a reciprocal key update

Implements Botan::TLS::Channel_Impl.

Definition at line 397 of file tls_channel_impl_12.cpp.

397 {
398 throw Invalid_Argument("cannot update traffic keys on a TLS 1.2 channel");
399}

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