Source code

Revision control

Copy as Markdown

Other Tools

/*
* 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_session.h>
#include <botan/tls_alert.h>
#include <botan/tls_session_manager.h>
#include <botan/tls_callbacks.h>
#include <botan/x509cert.h>
#include <functional>
#include <vector>
#include <string>
#include <map>
namespace Botan {
namespace TLS {
class Connection_Cipher_State;
class Connection_Sequence_Numbers;
class Handshake_State;
class Handshake_Message;
class Client_Hello;
class Server_Hello;
class Policy;
/**
* Generic interface for TLS endpoint
*/
class BOTAN_PUBLIC_API(2,0) Channel
{
public:
typedef std::function<void (const uint8_t[], size_t)> output_fn;
typedef std::function<void (const uint8_t[], size_t)> data_cb;
typedef std::function<void (Alert, const uint8_t[], size_t)> alert_cb;
typedef std::function<bool (const Session&)> handshake_cb;
typedef std::function<void (const Handshake_Message&)> handshake_msg_cb;
static size_t IO_BUF_DEFAULT_SIZE;
/**
* Set up a new TLS session
*
* @param callbacks contains a set of callback function references
* required by the TLS endpoint.
* @param session_manager manages session state
* @param rng a random number generator
* @param policy specifies other connection policy information
* @param is_server whether this is a server session or not
* @param is_datagram whether this is a DTLS session
* @param io_buf_sz This many bytes of memory will
* be preallocated for the read and write buffers. Smaller
* values just mean reallocations and copies are more likely.
*/
Channel(Callbacks& callbacks,
Session_Manager& session_manager,
RandomNumberGenerator& rng,
const Policy& policy,
bool is_server,
bool is_datagram,
size_t io_buf_sz = IO_BUF_DEFAULT_SIZE);
/**
* DEPRECATED. This constructor is only provided for backward
* compatibility and should not be used in new implementations.
* (Not marked deprecated since it is only called internally, by
* other deprecated constructors)
*/
Channel(output_fn out,
data_cb app_data_cb,
alert_cb alert_cb,
handshake_cb hs_cb,
handshake_msg_cb hs_msg_cb,
Session_Manager& session_manager,
RandomNumberGenerator& rng,
const Policy& policy,
bool is_server,
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 uint8_t 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<uint8_t>& buf);
/**
* Inject plaintext intended for counterparty
* Throws an exception if is_active() is false
*/
void send(const uint8_t 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();
virtual std::string application_protocol() const = 0;
protected:
virtual void process_handshake_msg(const Handshake_State* active_state,
Handshake_State& pending_state,
Handshake_Type type,
const std::vector<uint8_t>& contents,
bool epoch0_restart) = 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 Client_Hello* client_hello);
void secure_renegotiation_check(const Server_Hello* server_hello);
std::vector<uint8_t> secure_renegotiation_data_for_client_hello() const;
std::vector<uint8_t> 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);
Callbacks& callbacks() const { return m_callbacks; }
void reset_active_association_state();
private:
void init(size_t io_buf_sze);
void send_record(uint8_t record_type, const std::vector<uint8_t>& record);
void send_record_under_epoch(uint16_t epoch, uint8_t record_type,
const std::vector<uint8_t>& record);
void send_record_array(uint16_t epoch, uint8_t record_type,
const uint8_t input[], size_t length);
void write_record(Connection_Cipher_State* cipher_state,
uint16_t epoch, uint8_t type, const uint8_t input[], size_t length);
void reset_state();
Connection_Sequence_Numbers& sequence_numbers() const;
std::shared_ptr<Connection_Cipher_State> read_cipher_state_epoch(uint16_t epoch) const;
std::shared_ptr<Connection_Cipher_State> write_cipher_state_epoch(uint16_t epoch) const;
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(const secure_vector<uint8_t>& record,
uint64_t record_sequence,
Record_Type record_type,
Protocol_Version record_version,
bool epoch0_restart);
void process_application_data(uint64_t req_no, const secure_vector<uint8_t>& record);
void process_alert(const secure_vector<uint8_t>& record);
const bool m_is_server;
const bool m_is_datagram;
/* callbacks */
std::unique_ptr<Compat_Callbacks> m_compat_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<uint16_t, std::shared_ptr<Connection_Cipher_State>> m_write_cipher_states;
std::map<uint16_t, std::shared_ptr<Connection_Cipher_State>> m_read_cipher_states;
/* I/O buffers */
secure_vector<uint8_t> m_writebuf;
secure_vector<uint8_t> m_readbuf;
secure_vector<uint8_t> m_record_buf;
bool m_has_been_closed;
};
}
}
#endif