/* * TLS Channel * (C) 2011,2012,2014,2015 Jack Lloyd * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ #ifndef BOTAN_TLS_CHANNEL_H__ #define BOTAN_TLS_CHANNEL_H__ #include <botan/tls_policy.h> #include <botan/tls_session.h> #include <botan/tls_alert.h> #include <botan/tls_session_manager.h> #include <botan/x509cert.h> #include <vector> #include <string> #include <map> namespace Botan { namespace TLS { class Connection_Cipher_State; class Connection_Sequence_Numbers; class Handshake_State; class Handshake_Message; /** * Generic interface for TLS endpoint */ class BOTAN_DLL Channel { public: static size_t IO_BUF_DEFAULT_SIZE; class Callbacks { public: typedef std::function<void (const byte[], size_t)> output_fn; typedef std::function<void (const byte[], size_t)> data_cb; typedef std::function<void (Alert)> alert_cb; typedef std::function<bool (const Session&)> handshake_cb; typedef std::function<void (const Handshake_Message&)> handshake_msg_cb; /** * Encapsulates a set of callback functions required by a TLS Channel. * @param output_fn is called with data for the outbound socket * * @param app_data_cb is called when new application data is received * * @param alert_cb is called when a TLS alert is received * * @param handshake_cb is called when a handshake is completed */ Callbacks(output_fn out, data_cb app_data_cb, alert_cb alert_cb, handshake_cb hs_cb) : m_output_function(out), m_app_data_cb(app_data_cb), m_alert_cb(alert_cb), m_hs_cb(hs_cb), m_hs_msg_cb() {} Callbacks(output_fn out, data_cb app_data_cb, alert_cb alert_cb, handshake_cb hs_cb, handshake_msg_cb hs_msg_cb) : m_output_function(out), m_app_data_cb(app_data_cb), m_alert_cb(alert_cb), m_hs_cb(hs_cb), m_hs_msg_cb(hs_msg_cb) {} const output_fn& out_fn() const { return m_output_function; } const data_cb& app_data() const { return m_app_data_cb; } const alert_cb& alert() const { return m_alert_cb; } const handshake_cb& handshake() const { return m_hs_cb; } const handshake_msg_cb& handshake_msg() const { return m_hs_msg_cb; } private: const output_fn m_output_function; const data_cb m_app_data_cb; const alert_cb m_alert_cb; const handshake_cb m_hs_cb; const handshake_msg_cb m_hs_msg_cb; }; Channel(const Callbacks& callbacks, Session_Manager& session_manager, RandomNumberGenerator& rng, const Policy& policy, bool is_datagram, size_t io_buf_sz = IO_BUF_DEFAULT_SIZE); Channel(const Channel&) = delete; Channel& operator=(const Channel&) = delete; virtual ~Channel(); /** * Inject TLS traffic received from counterparty * @return a hint as the how many more bytes we need to process the * current record (this may be 0 if on a record boundary) */ size_t received_data(const byte buf[], size_t buf_size); /** * Inject TLS traffic received from counterparty * @return a hint as the how many more bytes we need to process the * current record (this may be 0 if on a record boundary) */ size_t received_data(const std::vector<byte>& buf); /** * Inject plaintext intended for counterparty * Throws an exception if is_active() is false */ void send(const byte buf[], size_t buf_size); /** * Inject plaintext intended for counterparty * Throws an exception if is_active() is false */ void send(const std::string& val); /** * Inject plaintext intended for counterparty * Throws an exception if is_active() is false */ template<typename Alloc> void send(const std::vector<unsigned char, Alloc>& val) { send(val.data(), val.size()); } /** * Send a TLS alert message. If the alert is fatal, the internal * state (keys, etc) will be reset. * @param alert the Alert to send */ void send_alert(const Alert& alert); /** * Send a warning alert */ void send_warning_alert(Alert::Type type) { send_alert(Alert(type, false)); } /** * Send a fatal alert */ void send_fatal_alert(Alert::Type type) { send_alert(Alert(type, true)); } /** * Send a close notification alert */ void close() { send_warning_alert(Alert::CLOSE_NOTIFY); } /** * @return true iff the connection is active for sending application data */ bool is_active() const; /** * @return true iff the connection has been definitely closed */ bool is_closed() const; /** * @return certificate chain of the peer (may be empty) */ std::vector<X509_Certificate> peer_cert_chain() const; /** * Key material export (RFC 5705) * @param label a disambiguating label string * @param context a per-association context value * @param length the length of the desired key in bytes * @return key of length bytes */ SymmetricKey key_material_export(const std::string& label, const std::string& context, size_t length) const; /** * Attempt to renegotiate the session * @param force_full_renegotiation if true, require a full renegotiation, * otherwise allow session resumption */ void renegotiate(bool force_full_renegotiation = false); /** * @return true iff the counterparty supports the secure * renegotiation extensions. */ bool secure_renegotiation_supported() const; /** * Perform a handshake timeout check. This does nothing unless * this is a DTLS channel with a pending handshake state, in * which case we check for timeout and potentially retransmit * handshake packets. */ bool timeout_check(); protected: virtual void process_handshake_msg(const Handshake_State* active_state, Handshake_State& pending_state, Handshake_Type type, const std::vector<byte>& contents) = 0; virtual void initiate_handshake(Handshake_State& state, bool force_full_renegotiation) = 0; virtual std::vector<X509_Certificate> get_peer_cert_chain(const Handshake_State& state) const = 0; virtual Handshake_State* new_handshake_state(class Handshake_IO* io) = 0; Handshake_State& create_handshake_state(Protocol_Version version); void inspect_handshake_message(const Handshake_Message& msg); void activate_session(); void change_cipher_spec_reader(Connection_Side side); void change_cipher_spec_writer(Connection_Side side); /* secure renegotiation handling */ void secure_renegotiation_check(const class Client_Hello* client_hello); void secure_renegotiation_check(const class Server_Hello* server_hello); std::vector<byte> secure_renegotiation_data_for_client_hello() const; std::vector<byte> secure_renegotiation_data_for_server_hello() const; RandomNumberGenerator& rng() { return m_rng; } Session_Manager& session_manager() { return m_session_manager; } const Policy& policy() const { return m_policy; } bool save_session(const Session& session) const { return m_callbacks.handshake()(session); } Callbacks get_callbacks() const { return m_callbacks; } private: void send_record(byte record_type, const std::vector<byte>& record); void send_record_under_epoch(u16bit epoch, byte record_type, const std::vector<byte>& record); void send_record_array(u16bit epoch, byte record_type, const byte input[], size_t length); void write_record(Connection_Cipher_State* cipher_state, u16bit epoch, byte type, const byte input[], size_t length); Connection_Sequence_Numbers& sequence_numbers() const; std::shared_ptr<Connection_Cipher_State> read_cipher_state_epoch(u16bit epoch) const; std::shared_ptr<Connection_Cipher_State> write_cipher_state_epoch(u16bit epoch) const; void reset_state(); const Handshake_State* active_state() const { return m_active_state.get(); } const Handshake_State* pending_state() const { return m_pending_state.get(); } /* methods to handle incoming traffic through Channel::receive_data. */ void process_handshake_ccs(secure_vector<byte>& record, u64bit& record_sequence, Record_Type& record_type, Protocol_Version& record_version); void process_application_data(secure_vector<byte>& record); void process_alert(secure_vector<byte>& record); bool m_is_datagram; /* callbacks */ Callbacks m_callbacks; /* external state */ Session_Manager& m_session_manager; const Policy& m_policy; RandomNumberGenerator& m_rng; /* sequence number state */ std::unique_ptr<Connection_Sequence_Numbers> m_sequence_numbers; /* pending and active connection states */ std::unique_ptr<Handshake_State> m_active_state; std::unique_ptr<Handshake_State> m_pending_state; /* cipher states for each epoch */ std::map<u16bit, std::shared_ptr<Connection_Cipher_State>> m_write_cipher_states; std::map<u16bit, std::shared_ptr<Connection_Cipher_State>> m_read_cipher_states; /* I/O buffers */ secure_vector<byte> m_writebuf; secure_vector<byte> m_readbuf; }; } } #endif