From d4f3e7c4ac584daa9d7e1ae10cb3412e450e25cf Mon Sep 17 00:00:00 2001 From: Matthias Gierlings Date: Fri, 29 Apr 2016 20:44:30 +0200 Subject: Reduction of code complexity in TLS classes. -reduced number of parameters in various methods -reduced cyclomatic complexity (McCabe-Metric) -removed "TLSEXT_HEARTBEAT_SUPPORT" from tls_extensions.h (leftover from heartbeat extension removal?) --- src/tests/unit_tls.cpp | 52 +++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 22 deletions(-) (limited to 'src/tests/unit_tls.cpp') diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index f125bfcb5..6e6ac29a0 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -1,5 +1,6 @@ /* * (C) 2014,2015 Jack Lloyd +* 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -218,10 +219,12 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, { std::vector c2s_traffic, s2c_traffic, client_recv, server_recv, client_sent, server_sent; - Botan::TLS::Server server(queue_inserter(s2c_traffic), - queue_inserter(server_recv), - print_alert, - handshake_complete, + + Botan::TLS::Server server(Botan::TLS::Server::Callbacks( + queue_inserter(s2c_traffic), + queue_inserter(server_recv), + print_alert, + handshake_complete), server_sessions, creds, policy, @@ -229,17 +232,19 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, next_protocol_chooser, false); - Botan::TLS::Client client(queue_inserter(c2s_traffic), - queue_inserter(client_recv), - print_alert, - handshake_complete, + Botan::TLS::Client::Callbacks client_callbacks(queue_inserter(c2s_traffic), + queue_inserter(client_recv), + print_alert, + handshake_complete); + Botan::TLS::Client client(client_callbacks, client_sessions, creds, policy, rng, - Botan::TLS::Server_Information("server.example.com"), - offer_version, - protocols_offered); + Botan::TLS::Client::Properties( + Botan::TLS::Server_Information("server.example.com"), + offer_version, + protocols_offered)); size_t rounds = 0; @@ -444,10 +449,11 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, { std::vector c2s_traffic, s2c_traffic, client_recv, server_recv, client_sent, server_sent; - Botan::TLS::Server server(queue_inserter(s2c_traffic), - queue_inserter(server_recv), - print_alert, - handshake_complete, + Botan::TLS::Server::Callbacks server_callbacks(queue_inserter(s2c_traffic), + queue_inserter(server_recv), + print_alert, + handshake_complete); + Botan::TLS::Server server(server_callbacks, server_sessions, creds, policy, @@ -455,17 +461,19 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, next_protocol_chooser, true); - Botan::TLS::Client client(queue_inserter(c2s_traffic), - queue_inserter(client_recv), - print_alert, - handshake_complete, + Botan::TLS::Client::Callbacks client_callbacks(queue_inserter(c2s_traffic), + queue_inserter(client_recv), + print_alert, + handshake_complete); + Botan::TLS::Client client(client_callbacks, client_sessions, creds, policy, rng, - Botan::TLS::Server_Information("server.example.com"), - offer_version, - protocols_offered); + Botan::TLS::Client::Properties( + Botan::TLS::Server_Information("server.example.com"), + offer_version, + protocols_offered)); size_t rounds = 0; -- cgit v1.2.3 From 89b75a5a36c18a7593aa6bdbb472e301904a66b3 Mon Sep 17 00:00:00 2001 From: Matthias Gierlings Date: Fri, 13 May 2016 00:42:16 +0200 Subject: Implemented Feedback on GH #457 - Removed deprecated TLS-Alert-Callback parameters. - Fixed improper naming of accessor for ALPN-Strings in tls_client.h - Fixed erroneous indentation on Ciphersuite Constructor. --- src/cli/tls_client.cpp | 4 ++-- src/cli/tls_proxy.cpp | 2 +- src/cli/tls_server.cpp | 4 ++-- src/lib/tls/tls_blocking.cpp | 4 ++-- src/lib/tls/tls_blocking.h | 2 +- src/lib/tls/tls_channel.cpp | 2 +- src/lib/tls/tls_channel.h | 2 +- src/lib/tls/tls_ciphersuite.h | 1 - src/lib/tls/tls_client.cpp | 4 ++-- src/lib/tls/tls_client.h | 10 +++++----- src/tests/unit_tls.cpp | 2 +- 11 files changed, 18 insertions(+), 19 deletions(-) (limited to 'src/tests/unit_tls.cpp') diff --git a/src/cli/tls_client.cpp b/src/cli/tls_client.cpp index 7db8bacf8..f6cc2e518 100644 --- a/src/cli/tls_client.cpp +++ b/src/cli/tls_client.cpp @@ -122,7 +122,7 @@ class TLS_Client final : public Command Botan::TLS::Client client(Botan::TLS::Client::Callbacks( socket_write, std::bind(&TLS_Client::process_data, this, _1, _2), - std::bind(&TLS_Client::alert_received, this, _1, _2, _3), + std::bind(&TLS_Client::alert_received, this, _1), std::bind(&TLS_Client::handshake_complete, this, _1)), *session_mgr, creds, @@ -315,7 +315,7 @@ class TLS_Client final : public Command } } - void alert_received(Botan::TLS::Alert alert, const uint8_t [], size_t ) + void alert_received(Botan::TLS::Alert alert) { output() << "Alert: " << alert.type_string() << "\n"; } diff --git a/src/cli/tls_proxy.cpp b/src/cli/tls_proxy.cpp index 054a8f8ca..6c5592faf 100644 --- a/src/cli/tls_proxy.cpp +++ b/src/cli/tls_proxy.cpp @@ -114,7 +114,7 @@ class tls_proxy_session : public boost::enable_shared_from_thishandshake_complete(session); } -void Blocking_Client::alert_cb(const Alert& alert, const byte[], size_t) +void Blocking_Client::alert_cb(const Alert& alert) { this->alert_notification(alert); } diff --git a/src/lib/tls/tls_blocking.h b/src/lib/tls/tls_blocking.h index 47c5c7483..51f860008 100644 --- a/src/lib/tls/tls_blocking.h +++ b/src/lib/tls/tls_blocking.h @@ -88,7 +88,7 @@ class BOTAN_DLL Blocking_Client void data_cb(const byte data[], size_t data_len); - void alert_cb(const Alert& alert, const byte data[], size_t data_len); + void alert_cb(const Alert& alert); read_fn m_read; TLS::Client m_channel; diff --git a/src/lib/tls/tls_channel.cpp b/src/lib/tls/tls_channel.cpp index 2c7e80feb..6300bd52b 100644 --- a/src/lib/tls/tls_channel.cpp +++ b/src/lib/tls/tls_channel.cpp @@ -419,7 +419,7 @@ void Channel::process_alert(secure_vector& record) if(alert_msg.type() == Alert::NO_RENEGOTIATION) m_pending_state.reset(); - m_callbacks.alert()(alert_msg, nullptr, 0); + m_callbacks.alert()(alert_msg); if(alert_msg.is_fatal()) { diff --git a/src/lib/tls/tls_channel.h b/src/lib/tls/tls_channel.h index c9ea8edde..71356f382 100644 --- a/src/lib/tls/tls_channel.h +++ b/src/lib/tls/tls_channel.h @@ -40,7 +40,7 @@ class BOTAN_DLL Channel public: typedef std::function output_fn; typedef std::function data_cb; - typedef std::function alert_cb; + typedef std::function alert_cb; typedef std::function handshake_cb; typedef std::function handshake_msg_cb; /** diff --git a/src/lib/tls/tls_ciphersuite.h b/src/lib/tls/tls_ciphersuite.h index 71596897c..cf9e1587b 100644 --- a/src/lib/tls/tls_ciphersuite.h +++ b/src/lib/tls/tls_ciphersuite.h @@ -128,7 +128,6 @@ class BOTAN_DLL Ciphersuite const char* mac_algo, size_t mac_keylen, const char* prf_algo = ""); - u16bit m_ciphersuite_code = 0; /* diff --git a/src/lib/tls/tls_client.cpp b/src/lib/tls/tls_client.cpp index ff4b20bbf..cc94aa11a 100644 --- a/src/lib/tls/tls_client.cpp +++ b/src/lib/tls/tls_client.cpp @@ -58,8 +58,8 @@ Client::Client(const Callbacks& callbacks, const std::string srp_identifier = m_creds.srp_identifier("tls-client", m_info.hostname()); Handshake_State& state = create_handshake_state(properties.get_protocol_version()); - send_client_hello(state, false, properties.get_protocol_version(), - srp_identifier, properties.get_next_protocol_versions()); + send_client_hello(state, false, properties.get_protocol_version(), + srp_identifier, properties.get_next_protocols()); } Handshake_State* Client::new_handshake_state(Handshake_IO* io) diff --git a/src/lib/tls/tls_client.h b/src/lib/tls/tls_client.h index e80739010..f73de0108 100644 --- a/src/lib/tls/tls_client.h +++ b/src/lib/tls/tls_client.h @@ -67,7 +67,7 @@ class BOTAN_DLL Client final : public Channel = {}) : m_server_info(server_info), m_protocol_version(protocol_version), - m_next_protocol_versions(next_versions) {} + m_next_protocols(next_versions) {} const Server_Information& get_server_info() { @@ -79,15 +79,15 @@ class BOTAN_DLL Client final : public Channel return m_protocol_version; } - const std::vector& get_next_protocol_versions() - { - return m_next_protocol_versions; + const std::vector& get_next_protocols() + { + return m_next_protocols; } private: const Server_Information& m_server_info; const Protocol_Version m_protocol_version; - const std::vector& m_next_protocol_versions; + const std::vector& m_next_protocols; }; Client(const Callbacks& callbacks, Session_Manager& session_manager, diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index 6e6ac29a0..d520752ee 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -162,7 +162,7 @@ std::function queue_inserter(std::vector& q) return [&](const byte buf[], size_t sz) { q.insert(q.end(), buf, buf + sz); }; } -void print_alert(Botan::TLS::Alert, const byte[], size_t) +void print_alert(Botan::TLS::Alert) { } -- cgit v1.2.3 From 93df95db45fa126725808fbd53aa978b00cf08ad Mon Sep 17 00:00:00 2001 From: Matthias Gierlings Date: Mon, 16 May 2016 20:46:50 +0200 Subject: Added virtual Callback Interface - extracted inner class TLS::Channel::Callbacks to stand-alone class TLS::Callbacks. - provided default implementations for TLS::Callbacks members executing calls to std::function members for backward compatibility. - applied changes to cli, tests and TLS::Channel related classes to be compatible with new interface. --- src/cli/tls_client.cpp | 2 +- src/cli/tls_server.cpp | 2 +- src/lib/tls/info.txt | 1 + src/lib/tls/tls_blocking.cpp | 2 +- src/lib/tls/tls_callbacks.h | 97 ++++++++++++++++++++++++++++++++++++++++++++ src/lib/tls/tls_channel.cpp | 6 +-- src/lib/tls/tls_channel.h | 47 +-------------------- src/lib/tls/tls_client.cpp | 5 ++- src/lib/tls/tls_client.h | 2 +- src/lib/tls/tls_server.cpp | 5 ++- src/tests/unit_tls.cpp | 26 ++++++------ 11 files changed, 128 insertions(+), 67 deletions(-) create mode 100644 src/lib/tls/tls_callbacks.h (limited to 'src/tests/unit_tls.cpp') diff --git a/src/cli/tls_client.cpp b/src/cli/tls_client.cpp index f6cc2e518..2e7daed6e 100644 --- a/src/cli/tls_client.cpp +++ b/src/cli/tls_client.cpp @@ -119,7 +119,7 @@ class TLS_Client final : public Command version = Botan::TLS::Protocol_Version::TLS_V11; } - Botan::TLS::Client client(Botan::TLS::Client::Callbacks( + Botan::TLS::Client client(Botan::TLS::Callbacks( socket_write, std::bind(&TLS_Client::process_data, this, _1, _2), std::bind(&TLS_Client::alert_received, this, _1), diff --git a/src/cli/tls_server.cpp b/src/cli/tls_server.cpp index c9f0b0a79..dffd30f66 100644 --- a/src/cli/tls_server.cpp +++ b/src/cli/tls_server.cpp @@ -107,7 +107,7 @@ class TLS_Server final : public Command } }; - Botan::TLS::Server server(Botan::TLS::Server::Callbacks( + Botan::TLS::Server server(Botan::TLS::Callbacks( socket_write, proc_fn, std::bind(&TLS_Server::alert_received, this, _1), diff --git a/src/lib/tls/info.txt b/src/lib/tls/info.txt index de15a65e5..b62adc17f 100644 --- a/src/lib/tls/info.txt +++ b/src/lib/tls/info.txt @@ -6,6 +6,7 @@ load_on auto credentials_manager.h tls_alert.h tls_blocking.h +tls_callbacks.h tls_channel.h tls_ciphersuite.h tls_client.h diff --git a/src/lib/tls/tls_blocking.cpp b/src/lib/tls/tls_blocking.cpp index 4c78a44ce..88397336b 100644 --- a/src/lib/tls/tls_blocking.cpp +++ b/src/lib/tls/tls_blocking.cpp @@ -22,7 +22,7 @@ Blocking_Client::Blocking_Client(read_fn reader, RandomNumberGenerator& rng, TLS::Client::Properties& properties) : m_read(reader), - m_channel(TLS::Client::Callbacks( + m_channel(TLS::Callbacks( writer, std::bind(&Blocking_Client::data_cb, this, _1, _2), std::bind(&Blocking_Client::alert_cb, this, _1), diff --git a/src/lib/tls/tls_callbacks.h b/src/lib/tls/tls_callbacks.h new file mode 100644 index 000000000..854054c2b --- /dev/null +++ b/src/lib/tls/tls_callbacks.h @@ -0,0 +1,97 @@ +/* +* TLS Callbacks +* (C) 2016 Matthias Gierlings +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_TLS_CALLBACKS_H__ +#define BOTAN_TLS_CALLBACKS_H__ + +#include +#include +namespace Botan { + +namespace TLS { + +class Handshake_State; +class Handshake_Message; + +/** +* Virtual Interface for TLS-Channel related callback handling. The default +* implementations involving std::function are only provided for compatibility +* purposes. New implementations should override the virtual member methods +* out_fn(), app_data(), alert(), handshake() and handshake_msg() instead. +* +*/ +class BOTAN_DLL Callbacks + { + public: + typedef std::function output_fn; + typedef std::function data_cb; + typedef std::function alert_cb; + typedef std::function handshake_cb; + typedef std::function handshake_msg_cb; + + /** + * DEPRECATED: This constructor is only provided for backward + * compatibility. New implementations should override the + * virtual member methods out_fn(), app_data(), alert(), + * handshake() and handshake_msg() and use the default constructor + * Callbacks(). + * + * 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, handshake_msg_cb hs_msg_cb = nullptr) + : 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) {} + + virtual ~Callbacks() {} + + virtual void out_fn(const byte data[], size_t size) const + { + if (m_output_function != nullptr) { m_output_function(data, size); } + } + + virtual void app_data(const byte data[], size_t size) const + { + if (m_app_data_cb != nullptr) { m_app_data_cb(data, size); } + } + + virtual void alert(Alert alert) const + { + if (m_alert_cb != nullptr) { m_alert_cb(alert); } + } + + virtual bool handshake(const Session& session) const + { + if (m_hs_cb != nullptr) { return m_hs_cb(session); } + } + + virtual void handshake_msg(const Handshake_Message& hmsg) + { + if (m_hs_msg_cb != nullptr) { m_hs_msg_cb(hmsg); } + } + + 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; + }; + +} + +} + +#endif diff --git a/src/lib/tls/tls_channel.cpp b/src/lib/tls/tls_channel.cpp index 6300bd52b..9bd3e5603 100644 --- a/src/lib/tls/tls_channel.cpp +++ b/src/lib/tls/tls_channel.cpp @@ -409,7 +409,7 @@ void Channel::process_application_data(secure_vector& record) * following record. Avoid spurious callbacks. */ if(record.size() > 0) - m_callbacks.app_data()(record.data(), record.size()); + m_callbacks.app_data(record.data(), record.size()); } void Channel::process_alert(secure_vector& record) @@ -419,7 +419,7 @@ void Channel::process_alert(secure_vector& record) if(alert_msg.type() == Alert::NO_RENEGOTIATION) m_pending_state.reset(); - m_callbacks.alert()(alert_msg); + m_callbacks.alert(alert_msg); if(alert_msg.is_fatal()) { @@ -454,7 +454,7 @@ void Channel::write_record(Connection_Cipher_State* cipher_state, u16bit epoch, cipher_state, m_rng); - m_callbacks.out_fn()(m_writebuf.data(), m_writebuf.size()); + m_callbacks.out_fn(m_writebuf.data(), m_writebuf.size()); } void Channel::send_record_array(u16bit epoch, byte type, const byte input[], size_t length) diff --git a/src/lib/tls/tls_channel.h b/src/lib/tls/tls_channel.h index 71356f382..d10ac2b6e 100644 --- a/src/lib/tls/tls_channel.h +++ b/src/lib/tls/tls_channel.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -35,50 +36,6 @@ class BOTAN_DLL Channel public: static size_t IO_BUF_DEFAULT_SIZE; - class Callbacks - { - public: - typedef std::function output_fn; - typedef std::function data_cb; - typedef std::function alert_cb; - typedef std::function handshake_cb; - typedef std::function 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, @@ -237,7 +194,7 @@ class BOTAN_DLL Channel const Policy& policy() const { return m_policy; } - bool save_session(const Session& session) const { return m_callbacks.handshake()(session); } + bool save_session(const Session& session) const { return m_callbacks.handshake(session); } Callbacks get_callbacks() const { return m_callbacks; } private: diff --git a/src/lib/tls/tls_client.cpp b/src/lib/tls/tls_client.cpp index cc94aa11a..ab733d7a5 100644 --- a/src/lib/tls/tls_client.cpp +++ b/src/lib/tls/tls_client.cpp @@ -64,7 +64,10 @@ Client::Client(const Callbacks& callbacks, Handshake_State* Client::new_handshake_state(Handshake_IO* io) { - return new Client_Handshake_State(io, get_callbacks().handshake_msg()); + return new Client_Handshake_State(io, + std::bind(&TLS::Callbacks::handshake_msg, + get_callbacks(), + std::placeholders::_1)); } std::vector diff --git a/src/lib/tls/tls_client.h b/src/lib/tls/tls_client.h index f73de0108..7fb4af89a 100644 --- a/src/lib/tls/tls_client.h +++ b/src/lib/tls/tls_client.h @@ -95,7 +95,7 @@ class BOTAN_DLL Client final : public Channel const Policy& policy, RandomNumberGenerator& rng, Properties properties, - size_t reserved_io_buffer_size = 16*1024 + size_t reserved_io_buffer_size = TLS::Client::IO_BUF_DEFAULT_SIZE ); const std::string& application_protocol() const { return m_application_protocol; } diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp index b1fff5fec..f864df391 100644 --- a/src/lib/tls/tls_server.cpp +++ b/src/lib/tls/tls_server.cpp @@ -231,7 +231,10 @@ Server::Server(const Callbacks& callbacks, Handshake_State* Server::new_handshake_state(Handshake_IO* io) { std::unique_ptr state( - new Server_Handshake_State(io, get_callbacks().handshake_msg())); + new Server_Handshake_State(io, + std::bind(&TLS::Callbacks::handshake_msg, + get_callbacks(), + std::placeholders::_1))); state->set_expected_next(CLIENT_HELLO); return state.release(); diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index d520752ee..621a803c8 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -220,7 +220,7 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, std::vector c2s_traffic, s2c_traffic, client_recv, server_recv, client_sent, server_sent; - Botan::TLS::Server server(Botan::TLS::Server::Callbacks( + Botan::TLS::Server server(Botan::TLS::Callbacks( queue_inserter(s2c_traffic), queue_inserter(server_recv), print_alert, @@ -232,10 +232,10 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, next_protocol_chooser, false); - Botan::TLS::Client::Callbacks client_callbacks(queue_inserter(c2s_traffic), - queue_inserter(client_recv), - print_alert, - handshake_complete); + Botan::TLS::Callbacks client_callbacks(queue_inserter(c2s_traffic), + queue_inserter(client_recv), + print_alert, + handshake_complete); Botan::TLS::Client client(client_callbacks, client_sessions, creds, @@ -449,10 +449,10 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, { std::vector c2s_traffic, s2c_traffic, client_recv, server_recv, client_sent, server_sent; - Botan::TLS::Server::Callbacks server_callbacks(queue_inserter(s2c_traffic), - queue_inserter(server_recv), - print_alert, - handshake_complete); + Botan::TLS::Callbacks server_callbacks(queue_inserter(s2c_traffic), + queue_inserter(server_recv), + print_alert, + handshake_complete); Botan::TLS::Server server(server_callbacks, server_sessions, creds, @@ -461,10 +461,10 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, next_protocol_chooser, true); - Botan::TLS::Client::Callbacks client_callbacks(queue_inserter(c2s_traffic), - queue_inserter(client_recv), - print_alert, - handshake_complete); + Botan::TLS::Callbacks client_callbacks(queue_inserter(c2s_traffic), + queue_inserter(client_recv), + print_alert, + handshake_complete); Botan::TLS::Client client(client_callbacks, client_sessions, creds, -- cgit v1.2.3 From d73460df43b2d4d14b62a98e9bc66dfea02ab63d Mon Sep 17 00:00:00 2001 From: Matthias Gierlings Date: Tue, 24 May 2016 20:17:42 +0200 Subject: Extended TLS Unit Tests - Modified TLS & DTLS tests to use both, legacy constructor and new virtual callback interface based constructors. --- src/tests/unit_tls.cpp | 577 ++++++++++++++++++++++++++++--------------------- 1 file changed, 326 insertions(+), 251 deletions(-) (limited to 'src/tests/unit_tls.cpp') diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index 621a803c8..919c3c950 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -219,24 +219,27 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, { std::vector c2s_traffic, s2c_traffic, client_recv, server_recv, client_sent, server_sent; - - Botan::TLS::Server server(Botan::TLS::Callbacks( - queue_inserter(s2c_traffic), - queue_inserter(server_recv), + // TLS::Server object constructed by new constructor using virtual callback interface. + std::unique_ptr server( + new Botan::TLS::Server(Botan::TLS::Callbacks( + queue_inserter(s2c_traffic), + queue_inserter(server_recv), + print_alert, + handshake_complete), + server_sessions, + creds, + policy, + rng, + next_protocol_chooser, + false)); + + // TLS::Client object constructed by new constructor using virtual callback interface. + std::unique_ptr client( + new Botan::TLS::Client(Botan::TLS::Callbacks( + queue_inserter(c2s_traffic), + queue_inserter(client_recv), print_alert, handshake_complete), - server_sessions, - creds, - policy, - rng, - next_protocol_chooser, - false); - - Botan::TLS::Callbacks client_callbacks(queue_inserter(c2s_traffic), - queue_inserter(client_recv), - print_alert, - handshake_complete); - Botan::TLS::Client client(client_callbacks, client_sessions, creds, policy, @@ -244,143 +247,177 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, Botan::TLS::Client::Properties( Botan::TLS::Server_Information("server.example.com"), offer_version, - protocols_offered)); + protocols_offered))); size_t rounds = 0; - while(true) + // Test TLS using both new and legacy constructors. + for(size_t ctor_sel = 0; ctor_sel < 2; ctor_sel++) { - ++rounds; - - if(rounds > 25) + if(ctor_sel == 1) { - if(r <= 2) - result.test_failure("Still here after many rounds, deadlock?"); - break; + // TLS::Server object constructed by legacy constructor. + server = std::unique_ptr( + new Botan::TLS::Server(queue_inserter(s2c_traffic), + queue_inserter(server_recv), + print_alert, + handshake_complete, + server_sessions, + creds, + policy, + rng, + next_protocol_chooser, + false)); + + // TLS::Client object constructed by legacy constructor. + std::unique_ptr client( + new Botan::TLS::Client(queue_inserter(c2s_traffic), + queue_inserter(client_recv), + print_alert, + handshake_complete, + client_sessions, + creds, + policy, + rng, + Botan::TLS::Server_Information("server.example.com"), + offer_version, + protocols_offered)); } - if(handshake_done && (client.is_closed() || server.is_closed())) - break; - - if(client.is_active() && client_sent.empty()) + while(true) { - // Choose a len between 1 and 511 - const size_t c_len = 1 + rng.next_byte() + rng.next_byte(); - client_sent = unlock(rng.random_vec(c_len)); + ++rounds; - // TODO send in several records - client.send(client_sent); - } + if(rounds > 25) + { + if(r <= 2) + result.test_failure("Still here after many rounds, deadlock?"); + break; + } - if(server.is_active() && server_sent.empty()) - { - result.test_eq("server protocol", server.next_protocol(), "test/3"); + if(handshake_done && (client->is_closed() || server->is_closed())) + break; - const size_t s_len = 1 + rng.next_byte() + rng.next_byte(); - server_sent = unlock(rng.random_vec(s_len)); - server.send(server_sent); - } + if(client->is_active() && client_sent.empty()) + { + // Choose a len between 1 and 511 + const size_t c_len = 1 + rng.next_byte() + rng.next_byte(); + client_sent = unlock(rng.random_vec(c_len)); - const bool corrupt_client_data = (r == 3); - const bool corrupt_server_data = (r == 4); + // TODO send in several records + client->send(client_sent); + } - if(c2s_traffic.size() > 0) - { - /* - * Use this as a temp value to hold the queues as otherwise they - * might end up appending more in response to messages during the - * handshake. - */ - std::vector input; - std::swap(c2s_traffic, input); - - if(corrupt_server_data) + if(server->is_active() && server_sent.empty()) { - input = Test::mutate_vec(input, true); - size_t needed = server.received_data(input.data(), input.size()); - - size_t total_consumed = needed; + result.test_eq("server->protocol", server->next_protocol(), "test/3"); - while(needed > 0 && - result.test_lt("Never requesting more than max protocol len", needed, 18*1024) && - result.test_lt("Total requested is readonable", total_consumed, 128*1024)) - { - input.resize(needed); - Test::rng().randomize(input.data(), input.size()); - needed = server.received_data(input.data(), input.size()); - total_consumed += needed; - } + const size_t s_len = 1 + rng.next_byte() + rng.next_byte(); + server_sent = unlock(rng.random_vec(s_len)); + server->send(server_sent); } - else + + const bool corrupt_client_data = (r == 3); + const bool corrupt_server_data = (r == 4); + + if(c2s_traffic.size() > 0) { - size_t needed = server.received_data(input.data(), input.size()); - result.test_eq("full packet received", needed, 0); - } + /* + * Use this as a temp value to hold the queues as otherwise they + * might end up appending more in response to messages during the + * handshake. + */ + std::vector input; + std::swap(c2s_traffic, input); + + if(corrupt_server_data) + { + input = Test::mutate_vec(input, true); + size_t needed = server->received_data(input.data(), input.size()); - continue; - } + size_t total_consumed = needed; - if(s2c_traffic.size() > 0) - { - std::vector input; - std::swap(s2c_traffic, input); + while(needed > 0 && + result.test_lt("Never requesting more than max protocol len", needed, 18*1024) && + result.test_lt("Total requested is readonable", total_consumed, 128*1024)) + { + input.resize(needed); + Test::rng().randomize(input.data(), input.size()); + needed = server->received_data(input.data(), input.size()); + total_consumed += needed; + } + } + else + { + size_t needed = server->received_data(input.data(), input.size()); + result.test_eq("full packet received", needed, 0); + } + + continue; + } - if(corrupt_client_data) + if(s2c_traffic.size() > 0) { - input = Test::mutate_vec(input, true); - size_t needed = client.received_data(input.data(), input.size()); + std::vector input; + std::swap(s2c_traffic, input); - size_t total_consumed = 0; + if(corrupt_client_data) + { + input = Test::mutate_vec(input, true); + size_t needed = client->received_data(input.data(), input.size()); - while(needed > 0 && result.test_lt("Never requesting more than max protocol len", needed, 18*1024)) + size_t total_consumed = 0; + + while(needed > 0 && result.test_lt("Never requesting more than max protocol len", needed, 18*1024)) + { + input.resize(needed); + Test::rng().randomize(input.data(), input.size()); + needed = client->received_data(input.data(), input.size()); + total_consumed += needed; + } + } + else { - input.resize(needed); - Test::rng().randomize(input.data(), input.size()); - needed = client.received_data(input.data(), input.size()); - total_consumed += needed; + size_t needed = client->received_data(input.data(), input.size()); + result.test_eq("full packet received", needed, 0); } + + continue; } - else + + if(client_recv.size()) { - size_t needed = client.received_data(input.data(), input.size()); - result.test_eq("full packet received", needed, 0); + result.test_eq("client recv", client_recv, server_sent); } - continue; - } - - if(client_recv.size()) - { - result.test_eq("client recv", client_recv, server_sent); - } - - if(server_recv.size()) - { - result.test_eq("server recv", server_recv, client_sent); - } + if(server_recv.size()) + { + result.test_eq("server->recv", server_recv, client_sent); + } - if(r > 2) - { - if(client_recv.size() && server_recv.size()) + if(r > 2) { - result.test_failure("Negotiated in the face of data corruption " + std::to_string(r)); + if(client_recv.size() && server_recv.size()) + { + result.test_failure("Negotiated in the face of data corruption " + std::to_string(r)); + } } - } - if(client.is_closed() && server.is_closed()) - break; + if(client->is_closed() && server->is_closed()) + break; - if(server_recv.size() && client_recv.size()) - { - Botan::SymmetricKey client_key = client.key_material_export("label", "context", 32); - Botan::SymmetricKey server_key = server.key_material_export("label", "context", 32); + if(server_recv.size() && client_recv.size()) + { + Botan::SymmetricKey client_key = client->key_material_export("label", "context", 32); + Botan::SymmetricKey server_key = server->key_material_export("label", "context", 32); - result.test_eq("TLS key material export", client_key.bits_of(), server_key.bits_of()); + result.test_eq("TLS key material export", client_key.bits_of(), server_key.bits_of()); - if(r % 2 == 0) - client.close(); - else - server.close(); + if(r % 2 == 0) + client->close(); + else + server->close(); + } } } } @@ -449,23 +486,27 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, { std::vector c2s_traffic, s2c_traffic, client_recv, server_recv, client_sent, server_sent; - Botan::TLS::Callbacks server_callbacks(queue_inserter(s2c_traffic), - queue_inserter(server_recv), - print_alert, - handshake_complete); - Botan::TLS::Server server(server_callbacks, - server_sessions, - creds, - policy, - rng, - next_protocol_chooser, - true); - - Botan::TLS::Callbacks client_callbacks(queue_inserter(c2s_traffic), - queue_inserter(client_recv), - print_alert, - handshake_complete); - Botan::TLS::Client client(client_callbacks, + // TLS::Server object constructed by new constructor using virtual callback interface. + std::unique_ptr server( + new Botan::TLS::Server(Botan::TLS::Callbacks( + queue_inserter(s2c_traffic), + queue_inserter(server_recv), + print_alert, + handshake_complete), + server_sessions, + creds, + policy, + rng, + next_protocol_chooser, + true)); + + // TLS::Client object constructed by new constructor using virtual callback interface. + std::unique_ptr client( + new Botan::TLS::Client(Botan::TLS::Callbacks( + queue_inserter(c2s_traffic), + queue_inserter(client_recv), + print_alert, + handshake_complete), client_sessions, creds, policy, @@ -473,162 +514,196 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, Botan::TLS::Client::Properties( Botan::TLS::Server_Information("server.example.com"), offer_version, - protocols_offered)); + protocols_offered))); size_t rounds = 0; - while(true) + // Test DTLS using both new and legacy constructors. + for(size_t ctor_sel = 0; ctor_sel < 2; ctor_sel++) { - // TODO: client and server should be in different threads - std::this_thread::sleep_for(std::chrono::milliseconds(rng.next_byte() % 2)); - ++rounds; - - if(rounds > 100) + if(ctor_sel == 1) { - result.test_failure("Still here after many rounds"); - break; + // TLS::Server object constructed by legacy constructor. + server = std::unique_ptr( + new Botan::TLS::Server(queue_inserter(s2c_traffic), + queue_inserter(server_recv), + print_alert, + handshake_complete, + server_sessions, + creds, + policy, + rng, + next_protocol_chooser, + true)); + + // TLS::Client object constructed by legacy constructor. + std::unique_ptr client( + new Botan::TLS::Client(queue_inserter(c2s_traffic), + queue_inserter(client_recv), + print_alert, + handshake_complete, + client_sessions, + creds, + policy, + rng, + Botan::TLS::Server_Information("server.example.com"), + offer_version, + protocols_offered)); } - if(handshake_done && (client.is_closed() || server.is_closed())) - break; - - if(client.is_active() && client_sent.empty()) + while(true) { - // Choose a len between 1 and 511 and send random chunks: - const size_t c_len = 1 + rng.next_byte() + rng.next_byte(); - client_sent = unlock(rng.random_vec(c_len)); + // TODO: client and server should be in different threads + std::this_thread::sleep_for(std::chrono::milliseconds(rng.next_byte() % 2)); + ++rounds; - // TODO send multiple parts - client.send(client_sent); - } - - if(server.is_active() && server_sent.empty()) - { - result.test_eq("server ALPN", server.next_protocol(), "test/3"); - - const size_t s_len = 1 + rng.next_byte() + rng.next_byte(); - server_sent = unlock(rng.random_vec(s_len)); - server.send(server_sent); - } + if(rounds > 100) + { + result.test_failure("Still here after many rounds"); + break; + } - const bool corrupt_client_data = (r == 3 && rng.next_byte() % 3 <= 1 && rounds < 10); - const bool corrupt_server_data = (r == 4 && rng.next_byte() % 3 <= 1 && rounds < 10); + if(handshake_done && (client->is_closed() || server->is_closed())) + break; - if(c2s_traffic.size() > 0) - { - /* - * Use this as a temp value to hold the queues as otherwise they - * might end up appending more in response to messages during the - * handshake. - */ - std::vector input; - std::swap(c2s_traffic, input); - - if(corrupt_server_data) + if(client->is_active() && client_sent.empty()) { - try - { - input = Test::mutate_vec(input, true); - size_t needed = server.received_data(input.data(), input.size()); + // Choose a len between 1 and 511 and send random chunks: + const size_t c_len = 1 + rng.next_byte() + rng.next_byte(); + client_sent = unlock(rng.random_vec(c_len)); - if(needed > 0 && result.test_lt("Never requesting more than max protocol len", needed, 18*1024)) - { - input.resize(needed); - Test::rng().randomize(input.data(), input.size()); - client.received_data(input.data(), input.size()); - } - } - catch(std::exception&) - { - result.test_note("corruption caused server exception"); - } + // TODO send multiple parts + client->send(client_sent); } - else + + if(server->is_active() && server_sent.empty()) { - try - { - size_t needed = server.received_data(input.data(), input.size()); - result.test_eq("full packet received", needed, 0); - } - catch(std::exception& e) - { - result.test_failure("server error", e.what()); - } - } + result.test_eq("server ALPN", server->next_protocol(), "test/3"); - continue; - } + const size_t s_len = 1 + rng.next_byte() + rng.next_byte(); + server_sent = unlock(rng.random_vec(s_len)); + server->send(server_sent); + } - if(s2c_traffic.size() > 0) - { - std::vector input; - std::swap(s2c_traffic, input); + const bool corrupt_client_data = (r == 3 && rng.next_byte() % 3 <= 1 && rounds < 10); + const bool corrupt_server_data = (r == 4 && rng.next_byte() % 3 <= 1 && rounds < 10); - if(corrupt_client_data) + if(c2s_traffic.size() > 0) { - try + /* + * Use this as a temp value to hold the queues as otherwise they + * might end up appending more in response to messages during the + * handshake. + */ + std::vector input; + std::swap(c2s_traffic, input); + + if(corrupt_server_data) { - input = Test::mutate_vec(input, true); - size_t needed = client.received_data(input.data(), input.size()); - - if(needed > 0 && result.test_lt("Never requesting more than max protocol len", needed, 18*1024)) + try { - input.resize(needed); - Test::rng().randomize(input.data(), input.size()); - client.received_data(input.data(), input.size()); + input = Test::mutate_vec(input, true); + size_t needed = server->received_data(input.data(), input.size()); + + if(needed > 0 && result.test_lt("Never requesting more than max protocol len", needed, 18*1024)) + { + input.resize(needed); + Test::rng().randomize(input.data(), input.size()); + client->received_data(input.data(), input.size()); + } + } + catch(std::exception&) + { + result.test_note("corruption caused server exception"); } } - catch(std::exception&) + else { - result.test_note("corruption caused client exception"); + try + { + size_t needed = server->received_data(input.data(), input.size()); + result.test_eq("full packet received", needed, 0); + } + catch(std::exception& e) + { + result.test_failure("server error", e.what()); + } } + + continue; } - else + + if(s2c_traffic.size() > 0) { - try + std::vector input; + std::swap(s2c_traffic, input); + + if(corrupt_client_data) { - size_t needed = client.received_data(input.data(), input.size()); - result.test_eq("full packet received", needed, 0); + try + { + input = Test::mutate_vec(input, true); + size_t needed = client->received_data(input.data(), input.size()); + + if(needed > 0 && result.test_lt("Never requesting more than max protocol len", needed, 18*1024)) + { + input.resize(needed); + Test::rng().randomize(input.data(), input.size()); + client->received_data(input.data(), input.size()); + } + } + catch(std::exception&) + { + result.test_note("corruption caused client exception"); + } } - catch(std::exception& e) + else { - result.test_failure("client error", e.what()); + try + { + size_t needed = client->received_data(input.data(), input.size()); + result.test_eq("full packet received", needed, 0); + } + catch(std::exception& e) + { + result.test_failure("client error", e.what()); + } } - } - continue; - } + continue; + } - // If we corrupted a DTLS application message, resend it: - if(client.is_active() && corrupt_client_data && server_recv.empty()) - client.send(client_sent); - if(server.is_active() && corrupt_server_data && client_recv.empty()) - server.send(server_sent); + // If we corrupted a DTLS application message, resend it: + if(client->is_active() && corrupt_client_data && server_recv.empty()) + client->send(client_sent); + if(server->is_active() && corrupt_server_data && client_recv.empty()) + server->send(server_sent); - if(client_recv.size()) - { - result.test_eq("client recv", client_recv, server_sent); - } + if(client_recv.size()) + { + result.test_eq("client recv", client_recv, server_sent); + } - if(server_recv.size()) - { - result.test_eq("server recv", server_recv, client_sent); - } + if(server_recv.size()) + { + result.test_eq("server recv", server_recv, client_sent); + } - if(client.is_closed() && server.is_closed()) - break; + if(client->is_closed() && server->is_closed()) + break; - if(server_recv.size() && client_recv.size()) - { - Botan::SymmetricKey client_key = client.key_material_export("label", "context", 32); - Botan::SymmetricKey server_key = server.key_material_export("label", "context", 32); + if(server_recv.size() && client_recv.size()) + { + Botan::SymmetricKey client_key = client->key_material_export("label", "context", 32); + Botan::SymmetricKey server_key = server->key_material_export("label", "context", 32); - result.test_eq("key material export", client_key.bits_of(), server_key.bits_of()); + result.test_eq("key material export", client_key.bits_of(), server_key.bits_of()); - if(r % 2 == 0) - client.close(); - else - server.close(); + if(r % 2 == 0) + client->close(); + else + server->close(); + } } } } -- cgit v1.2.3 From 0d38a540cca29955a50acda165e6d8643793e846 Mon Sep 17 00:00:00 2001 From: Matthias Gierlings Date: Sun, 19 Jun 2016 20:23:19 +0200 Subject: Removed TLS::Session::Properties - Removed proposed wrapper class to logically group TLS session properties. --- src/cli/tls_client.cpp | 7 ++- src/lib/tls/tls_blocking.cpp | 8 ++- src/lib/tls/tls_blocking.h | 4 +- src/lib/tls/tls_client.cpp | 26 +++++----- src/lib/tls/tls_client.h | 62 ++++------------------- src/lib/tls/tls_server.cpp | 17 +++---- src/lib/tls/tls_session.cpp | 58 +++++++++++---------- src/lib/tls/tls_session.h | 118 ++++++++++--------------------------------- src/tests/unit_tls.cpp | 14 +++-- 9 files changed, 105 insertions(+), 209 deletions(-) (limited to 'src/tests/unit_tls.cpp') diff --git a/src/cli/tls_client.cpp b/src/cli/tls_client.cpp index 2e7daed6e..e2fc1f027 100644 --- a/src/cli/tls_client.cpp +++ b/src/cli/tls_client.cpp @@ -128,10 +128,9 @@ class TLS_Client final : public Command creds, *policy, rng(), - Botan::TLS::Client::Properties( - Botan::TLS::Server_Information(host, port), - version, - protocols_to_offer)); + Botan::TLS::Server_Information(host, port), + version, + protocols_to_offer); bool first_active = true; diff --git a/src/lib/tls/tls_blocking.cpp b/src/lib/tls/tls_blocking.cpp index 88397336b..3910d242c 100644 --- a/src/lib/tls/tls_blocking.cpp +++ b/src/lib/tls/tls_blocking.cpp @@ -20,7 +20,9 @@ Blocking_Client::Blocking_Client(read_fn reader, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, - TLS::Client::Properties& properties) : + const Server_Information& server_info, + const Protocol_Version& offer_version, + const std::vector& next) : m_read(reader), m_channel(TLS::Callbacks( writer, @@ -32,7 +34,9 @@ Blocking_Client::Blocking_Client(read_fn reader, creds, policy, rng, - properties) + server_info, + offer_version, + next) { } diff --git a/src/lib/tls/tls_blocking.h b/src/lib/tls/tls_blocking.h index 51f860008..cba44b524 100644 --- a/src/lib/tls/tls_blocking.h +++ b/src/lib/tls/tls_blocking.h @@ -39,7 +39,9 @@ class BOTAN_DLL Blocking_Client Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, - TLS::Client::Properties& properties); + const Server_Information& server_info = Server_Information(), + const Protocol_Version& offer_version = Protocol_Version::latest_tls_version(), + const std::vector& next_protos = {}); /** * Completes full handshake then returns diff --git a/src/lib/tls/tls_client.cpp b/src/lib/tls/tls_client.cpp index e2f090033..1708a7f40 100644 --- a/src/lib/tls/tls_client.cpp +++ b/src/lib/tls/tls_client.cpp @@ -48,14 +48,16 @@ Client::Client(const Callbacks& callbacks, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, - Properties properties, + const Server_Information& info, + const Protocol_Version& offer_version, + const std::vector& next_protos, size_t io_buf_sz) : - Channel(callbacks, session_manager, rng, policy, properties.get_protocol_version().is_datagram_protocol(), + Channel(callbacks, session_manager, rng, policy, offer_version.is_datagram_protocol(), io_buf_sz), m_creds(creds), - m_info(properties.get_server_info()) + m_info(info) { - init(properties.get_protocol_version(), properties.get_next_protocols()); + init(offer_version, next_protos); } Client::Client(output_fn output_fn, @@ -524,22 +526,20 @@ void Client::process_handshake_msg(const Handshake_State* active_state, if(session_id.empty() && !session_ticket.empty()) session_id = make_hello_random(rng(), policy()); - Session::Properties session_properties( - m_info, - "", - state.server_hello()->srtp_profile(), - state.server_hello()->version(), - state.server_hello()->ciphersuite(), - state.server_hello()->compression_method()); - Session session_info( session_id, state.session_keys().master_secret(), + state.server_hello()->version(), + state.server_hello()->ciphersuite(), + state.server_hello()->compression_method(), CLIENT, state.server_hello()->supports_extended_master_secret(), get_peer_cert_chain(state), session_ticket, - session_properties); + m_info, + "", + state.server_hello()->srtp_profile() + ); const bool should_save = save_session(session_info); diff --git a/src/lib/tls/tls_client.h b/src/lib/tls/tls_client.h index 8a45c5444..6452294cd 100644 --- a/src/lib/tls/tls_client.h +++ b/src/lib/tls/tls_client.h @@ -37,64 +37,18 @@ class BOTAN_DLL Client final : public Channel * * @param rng a random number generator * - * @param properties holds server information and protocol related - * properties. + * @param server_info is identifying information about the TLS server + * + * @param offer_version specifies which version we will offer + * to the TLS server. + * + * @param next_protocols specifies protocols to advertise with ALPN * * @param reserved_io_buffer_size This many bytes of memory will * be preallocated for the read and write buffers. Smaller * values just mean reallocations and copies are more likely. */ - class Properties - { - /** - * Stores TLS Client properties. - * - * @param server_info is identifying information about the TLS server - * - * @param protocol_version specifies which version we will offer - * to the TLS server. - * - * @param next_protocols specifies protocols to advertise with ALPN - */ - - public: - Properties(const Server_Information& server_info - = Server_Information(), - const Protocol_Version protocol_version - = Protocol_Version::latest_tls_version(), - const std::vector& next_versions - = {}) - : m_server_info(server_info), - m_protocol_version(protocol_version), - m_next_protocols(next_versions) {} - - const Server_Information& get_server_info() - { - return m_server_info; - } - - const Protocol_Version& get_protocol_version() - { - return m_protocol_version; - } - - const std::vector& get_next_protocols() - { - return m_next_protocols; - } - - private: - const Server_Information& m_server_info; - const Protocol_Version m_protocol_version; - const std::vector& m_next_protocols; - }; - - /** - * DEPRECATED. This constructor is only provided for backward - * compatibility and should not be used in new implementations. - */ - BOTAN_DEPRECATED("Use TLS::Client(TLS::Callbacks ...)") Client(output_fn out, data_cb app_data_cb, alert_cb alert_cb, @@ -134,7 +88,9 @@ class BOTAN_DLL Client final : public Channel Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, - Properties properties, + const Server_Information& server_info = Server_Information(), + const Protocol_Version& offer_version = Protocol_Version::latest_tls_version(), + const std::vector& next_protocols = {}, size_t reserved_io_buffer_size = TLS::Client::IO_BUF_DEFAULT_SIZE ); diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp index 39ebe2a59..ebd4d413d 100644 --- a/src/lib/tls/tls_server.cpp +++ b/src/lib/tls/tls_server.cpp @@ -494,23 +494,20 @@ void Server::process_finished_msg(Server_Handshake_State& pending_state, pending_state.hash().update ( pending_state.handshake_io().format ( contents, type ) ); - Session::Properties session_properties( - Server_Information(pending_state.client_hello()->sni_hostname()), - "", - pending_state.server_hello()->srtp_profile(), - pending_state.server_hello()->version(), - pending_state.server_hello()->ciphersuite(), - pending_state.server_hello()->compression_method()); - - Session session_info( pending_state.server_hello()->session_id(), pending_state.session_keys().master_secret(), + pending_state.server_hello()->version(), + pending_state.server_hello()->ciphersuite(), + pending_state.server_hello()->compression_method(), SERVER, pending_state.server_hello()->supports_extended_master_secret(), get_peer_cert_chain ( pending_state ), std::vector(), - session_properties); + Server_Information(pending_state.client_hello()->sni_hostname()), + pending_state.srp_identifier(), + pending_state.server_hello()->srtp_profile() + ); if ( save_session ( session_info ) ) { diff --git a/src/lib/tls/tls_session.cpp b/src/lib/tls/tls_session.cpp index bcbac10af..18c9b357c 100644 --- a/src/lib/tls/tls_session.cpp +++ b/src/lib/tls/tls_session.cpp @@ -1,7 +1,6 @@ /* * TLS Session State * (C) 2011-2012,2015 Jack Lloyd -* 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -20,19 +19,29 @@ namespace TLS { Session::Session(const std::vector& session_identifier, const secure_vector& master_secret, + Protocol_Version version, + u16bit ciphersuite, + byte compression_method, Connection_Side side, bool extended_master_secret, const std::vector& certs, const std::vector& ticket, - Properties properties) : + const Server_Information& server_info, + const std::string& srp_identifier, + u16bit srtp_profile) : m_start_time(std::chrono::system_clock::now()), m_identifier(session_identifier), m_session_ticket(ticket), m_master_secret(master_secret), + m_version(version), + m_ciphersuite(ciphersuite), + m_compression_method(compression_method), m_connection_side(side), + m_srtp_profile(srtp_profile), m_extended_master_secret(extended_master_secret), m_peer_certs(certs), - m_properties(properties) + m_server_info(server_info), + m_srp_identifier(srp_identifier) { } @@ -60,9 +69,6 @@ Session::Session(const byte ber[], size_t ber_len) size_t srtp_profile = 0; size_t fragment_size = 0; - u16bit cs = m_properties.get_ciphersuite(); - byte compr = compression_method(); - BER_Decoder(ber, ber_len) .start_cons(SEQUENCE) .decode_and_check(static_cast(TLS_SESSION_PARAM_STRUCT_VERSION), @@ -72,9 +78,10 @@ Session::Session(const byte ber[], size_t ber_len) .decode_integer_type(minor_version) .decode(m_identifier, OCTET_STRING) .decode(m_session_ticket, OCTET_STRING) - .decode_integer_type(cs) - .decode_integer_type(compr) + .decode_integer_type(m_ciphersuite) + .decode_integer_type(m_compression_method) .decode_integer_type(side_code) + .decode_integer_type(fragment_size) .decode(m_extended_master_secret) .decode(m_master_secret, OCTET_STRING) .decode(peer_cert_bits, OCTET_STRING) @@ -96,17 +103,16 @@ Session::Session(const byte ber[], size_t ber_len) " no longer supported"); } - m_properties.set_ciphersuite(cs); - m_properties.set_compression_method(compr); - m_properties.set_protocol_version(Protocol_Version(major_version, minor_version)); + m_version = Protocol_Version(major_version, minor_version); m_start_time = std::chrono::system_clock::from_time_t(start_time); m_connection_side = static_cast(side_code); - m_properties.set_srtp_profile(static_cast(srtp_profile)); - m_properties.set_server_info( - Server_Information(server_hostname.value(), - server_service.value(), - static_cast(server_port))); - m_properties.set_srp_identifier(srp_identifier_str.value()); + m_srtp_profile = static_cast(srtp_profile); + + m_server_info = Server_Information(server_hostname.value(), + server_service.value(), + static_cast(server_port)); + + m_srp_identifier = srp_identifier_str.value(); if(!peer_cert_bits.empty()) { @@ -127,22 +133,22 @@ secure_vector Session::DER_encode() const .start_cons(SEQUENCE) .encode(static_cast(TLS_SESSION_PARAM_STRUCT_VERSION)) .encode(static_cast(std::chrono::system_clock::to_time_t(m_start_time))) - .encode(static_cast(version().major_version())) - .encode(static_cast(version().minor_version())) + .encode(static_cast(m_version.major_version())) + .encode(static_cast(m_version.minor_version())) .encode(m_identifier, OCTET_STRING) .encode(m_session_ticket, OCTET_STRING) - .encode(static_cast(ciphersuite_code())) - .encode(static_cast(compression_method())) + .encode(static_cast(m_ciphersuite)) + .encode(static_cast(m_compression_method)) .encode(static_cast(m_connection_side)) .encode(static_cast(/*old fragment size*/0)) .encode(m_extended_master_secret) .encode(m_master_secret, OCTET_STRING) .encode(peer_cert_bits, OCTET_STRING) - .encode(ASN1_String(m_properties.get_server_info().hostname(), UTF8_STRING)) - .encode(ASN1_String(m_properties.get_server_info().service(), UTF8_STRING)) - .encode(static_cast(m_properties.get_server_info().port())) - .encode(ASN1_String(srp_identifier(), UTF8_STRING)) - .encode(static_cast(dtls_srtp_profile())) + .encode(ASN1_String(m_server_info.hostname(), UTF8_STRING)) + .encode(ASN1_String(m_server_info.service(), UTF8_STRING)) + .encode(static_cast(m_server_info.port())) + .encode(ASN1_String(m_srp_identifier, UTF8_STRING)) + .encode(static_cast(m_srtp_profile)) .end_cons() .get_contents(); } diff --git a/src/lib/tls/tls_session.h b/src/lib/tls/tls_session.h index 600aa0a10..8ca646cf2 100644 --- a/src/lib/tls/tls_session.h +++ b/src/lib/tls/tls_session.h @@ -1,7 +1,6 @@ /* * TLS Session * (C) 2011-2012,2015 Jack Lloyd -* 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -28,106 +27,35 @@ namespace TLS { class BOTAN_DLL Session { public: - class Properties - { - public: - Properties() : m_srtp_profile(0), m_protocol_version(), - m_ciphersuite(), m_compression_method(0) {} - - Properties(const Server_Information& server_info, - const std::string& srp_identifier, - u16bit srtp_profile, - Protocol_Version protocol_version, - u16bit ciphersuite, - byte compression_method) - : m_server_info(server_info), - m_srp_identifier(srp_identifier), - m_srtp_profile(srtp_profile), - m_protocol_version(protocol_version), - m_ciphersuite(ciphersuite), - m_compression_method(compression_method) {} - - const Server_Information& get_server_info() const - { - return m_server_info; - } - - void set_server_info(Server_Information server_info) - { - m_server_info = server_info; - } - - const std::string& get_srp_identifier() const - { - return m_srp_identifier; - } - - void set_srp_identifier(const std::string& srp_identifier) - { - m_srp_identifier = srp_identifier; - } - - u16bit get_srtp_profile() const { return m_srtp_profile; } - void set_srtp_profile(u16bit srtp_profile) - { - m_srtp_profile = srtp_profile; - } - - Protocol_Version get_protocol_version() const - { - return m_protocol_version; - } - - void set_protocol_version(Protocol_Version protocol_version) - { - m_protocol_version = protocol_version; - } - - u16bit get_ciphersuite() const { return m_ciphersuite; } - - void set_ciphersuite(u16bit ciphersuite) - { - m_ciphersuite = ciphersuite; - } - - byte get_compression_method() const - { - return m_compression_method; - } - - void set_compression_method(byte compression_method) - { - m_compression_method = compression_method; - } - - private: - Server_Information m_server_info; - std::string m_srp_identifier; - u16bit m_srtp_profile; - Protocol_Version m_protocol_version; - u16bit m_ciphersuite; - byte m_compression_method; - }; /** * Uninitialized session */ Session() : m_start_time(std::chrono::system_clock::time_point::min()), + m_version(), + m_ciphersuite(0), + m_compression_method(0), m_connection_side(static_cast(0)), - m_extended_master_secret(false), - m_properties() {} + m_srtp_profile(0), + m_extended_master_secret(false) + {} /** * New session (sets session start time) */ Session(const std::vector& session_id, const secure_vector& master_secret, + Protocol_Version version, + u16bit ciphersuite, + byte compression_method, Connection_Side side, bool supports_extended_master_secret, const std::vector& peer_certs, const std::vector& session_ticket, - Properties properties); + const Server_Information& server_info, + const std::string& srp_identifier, + u16bit srtp_profile); /** * Load a session from DER representation (created by DER_encode) @@ -184,22 +112,22 @@ class BOTAN_DLL Session /** * Get the version of the saved session */ - Protocol_Version version() const { return m_properties.get_protocol_version(); } + Protocol_Version version() const { return m_version; } /** * Get the ciphersuite code of the saved session */ - u16bit ciphersuite_code() const { return m_properties.get_ciphersuite(); } + u16bit ciphersuite_code() const { return m_ciphersuite; } /** * Get the ciphersuite info of the saved session */ - Ciphersuite ciphersuite() const { return Ciphersuite::by_id(ciphersuite_code()); } + Ciphersuite ciphersuite() const { return Ciphersuite::by_id(m_ciphersuite); } /** * Get the compression method used in the saved session */ - byte compression_method() const { return m_properties.get_compression_method(); } + byte compression_method() const { return m_compression_method; } /** * Get which side of the connection the resumed session we are/were @@ -210,7 +138,7 @@ class BOTAN_DLL Session /** * Get the SRP identity (if sent by the client in the initial handshake) */ - const std::string& srp_identifier() const { return m_properties.get_srp_identifier(); } + const std::string& srp_identifier() const { return m_srp_identifier; } /** * Get the saved master secret @@ -225,7 +153,7 @@ class BOTAN_DLL Session /** * Get the negotiated DTLS-SRTP algorithm (RFC 5764) */ - u16bit dtls_srtp_profile() const { return m_properties.get_srtp_profile(); } + u16bit dtls_srtp_profile() const { return m_srtp_profile; } bool supports_extended_master_secret() const { return m_extended_master_secret; } @@ -249,7 +177,7 @@ class BOTAN_DLL Session */ const std::vector& session_ticket() const { return m_session_ticket; } - const Server_Information& server_info() const { return m_properties.get_server_info(); } + const Server_Information& server_info() const { return m_server_info; } private: enum { TLS_SESSION_PARAM_STRUCT_VERSION = 20160103 }; @@ -260,10 +188,16 @@ class BOTAN_DLL Session std::vector m_session_ticket; // only used by client side secure_vector m_master_secret; + Protocol_Version m_version; + u16bit m_ciphersuite; + byte m_compression_method; Connection_Side m_connection_side; + u16bit m_srtp_profile; bool m_extended_master_secret; + std::vector m_peer_certs; - Properties m_properties; + Server_Information m_server_info; // optional + std::string m_srp_identifier; // optional }; } diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index 919c3c950..150ed2794 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -244,10 +244,9 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, creds, policy, rng, - Botan::TLS::Client::Properties( - Botan::TLS::Server_Information("server.example.com"), - offer_version, - protocols_offered))); + Botan::TLS::Server_Information("server.example.com"), + offer_version, + protocols_offered)); size_t rounds = 0; @@ -511,10 +510,9 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, creds, policy, rng, - Botan::TLS::Client::Properties( - Botan::TLS::Server_Information("server.example.com"), - offer_version, - protocols_offered))); + Botan::TLS::Server_Information("server.example.com"), + offer_version, + protocols_offered)); size_t rounds = 0; -- cgit v1.2.3 From a22a54fd962f4aafa7ea3d6a888d8d4ab779f1ba Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Fri, 12 Aug 2016 12:36:36 -0400 Subject: Changes to TLS::Callbacks for GH PR #457 Make TLS::Channel::m_callbacks a reference, so deriving from TLS::Callbacks works Split out the compat (std::function) based interface to Compat_Callbacks. This avoids the overhead of empty std::functions when using the virtual interface, and ensures the virtual interface works since there is no callback path that does not involve a vtable lookup. Rename the TLS::Callback functions. Since the idea is that often an owning class will pass *this as the callbacks argument, it is good to namespace the virtual functions so as not to conflict with other names chosen by the class. Specifically, prefixes all cb functions with tls_ Revert changes to use the old style alert callback (with no longer used data/len params) so no API changes are required for old code. The new Callbacks interface continues to just receive the alert code itself. Switch to virtual function interface in CLI tls_client for testing. Inline tls_server_handshake_state.h - only used in tls_server.cpp Fix tests - test looked like it was creating a new client object but it was not actually being used. And when enabled, it failed because the queues were not being emptied in between. So, fix that. --- doc/manual/tls.rst | 144 +++++++++++++++---------------- src/cli/tls_client.cpp | 38 ++++---- src/cli/tls_proxy.cpp | 17 ++-- src/cli/tls_server.cpp | 12 ++- src/lib/tls/info.txt | 1 - src/lib/tls/tls_blocking.cpp | 8 +- src/lib/tls/tls_blocking.h | 2 + src/lib/tls/tls_callbacks.h | 106 ++++++++++++++++------- src/lib/tls/tls_channel.cpp | 31 +++---- src/lib/tls/tls_channel.h | 23 ++--- src/lib/tls/tls_client.cpp | 9 +- src/lib/tls/tls_client.h | 57 +++++++++--- src/lib/tls/tls_handshake_state.cpp | 10 ++- src/lib/tls/tls_handshake_state.h | 14 +-- src/lib/tls/tls_record.h | 4 - src/lib/tls/tls_server.cpp | 36 ++++++-- src/lib/tls/tls_server.h | 23 ++++- src/lib/tls/tls_server_handshake_state.h | 48 ----------- src/tests/unit_tls.cpp | 93 ++++++++++++-------- 19 files changed, 376 insertions(+), 300 deletions(-) delete mode 100644 src/lib/tls/tls_server_handshake_state.h (limited to 'src/tests/unit_tls.cpp') diff --git a/doc/manual/tls.rst b/doc/manual/tls.rst index a10a4280c..7210fc092 100644 --- a/doc/manual/tls.rst +++ b/doc/manual/tls.rst @@ -22,44 +22,52 @@ instance, by reading from a network socket) it passes that information to TLS using :cpp:func:`TLS::Channel::received_data`. If the data passed in results in some change in the state, such as a handshake completing, or some data or an alert being received from the other -side, then a user provided callback will be invoked. If the reader is -familiar with OpenSSL's BIO layer, it might be analagous to saying the -only way of interacting with Botan's TLS is via a `BIO_mem` I/O +side, then the appropriate user provided callback will be invoked. + +If the reader is familiar with OpenSSL's BIO layer, it might be analagous +to saying the only way of interacting with Botan's TLS is via a `BIO_mem` I/O abstraction. This makes the library completely agnostic to how you write your network layer, be it blocking sockets, libevent, asio, a -message queue, etc. +message queue, lwIP on RTOS, some carrier pidgeons, etc. -The callbacks for TLS have the signatures +Starting in 1.11.31, the application callbacks are encapsulated as the class +``TLS::Callbacks`` with the following members. The first four (``tls_emit_data``, +``tls_record_received``, ``tls_alert``, and ``tls_session_established``) are +mandatory for using TLS, all others are optional and provide additional +information about the connection. - .. cpp:function:: void output_fn(const byte data[], size_t data_len) + .. cpp:function:: void tls_emit_data(const byte data[], size_t data_len) - TLS requests that all bytes of *data* be queued up to send to the - counterparty. After this function returns, *data* will be - overwritten, so a copy of the input must be made if the callback + The TLS stack requests that all bytes of *data* be queued up to send to the + counterparty. After this function returns, the buffer containing *data* will + be overwritten, so a copy of the input must be made if the callback cannot send the data immediately. - .. cpp:function:: void data_cb(const byte data[], size_t data_len) + The write can be deferred but for TLS all writes must occur *in order*. + For DTLS this is not strictly required, but is still recommended. + + .. cpp:function:: void tls_record_received(uint64_t rec_no, const byte data[], size_t data_len) + + Called once for each application_data record which is received, with the + matching (TLS level) record sequence number. - Called whenever application data is received from the other side - of the connection, in which case *data* and *data_len* specify - the data received. This array will be overwritten sometime after - the callback returns, so again a copy should be made if need be. + Currently empty records are ignored and do not instigate a callback, + but this may change in a future release. - .. cpp:function:: void alert_cb(Alert alert, const byte data[], size_t data_len) + As with ``tls_emit_data``, the array will be overwritten sometime after + the callback returns, so a copy should be made if needed. - Called when an alert is received. Normally, data is null and - data_len is 0, as most alerts have no associated data. However, - if TLS heartbeats (see :rfc:`6520`) were negotiated, and we - initiated a heartbeat, then if/when the other party responds, - ``alert_cb`` will be called with whatever data was included in - the heartbeat response (if any) along with a psuedo-alert value - of ``HEARTBEAT_PAYLOAD``. + .. cpp:function:: void tls_alert(Alert alert) - .. cpp:function:: bool handshake_cb(const TLS::Session& session) + Called when an alert is received from the peer. Note that alerts + received before the handshake is complete are not authenticated and + could have been inserted by a MITM attacker. + + .. cpp:function:: bool tls_session_established(const TLS::Session& session) Called whenever a negotiation completes. This can happen more - than once on any connection. The *session* parameter provides - information about the session which was established. + than once on any connection, if renegotiation occurs. The *session* parameter + provides information about the session which was just established. If this function returns false, the session will not be cached for later resumption. @@ -68,8 +76,22 @@ The callbacks for TLS have the signatures exception which will send a close message to the counterparty and reset the connection state. -You can of course use tools like ``std::bind`` to bind additional -parameters to your callback functions. + .. cpp:function:: void tls_inspect_handshake_msg(const Handshake_Message&) + + This callback is optional, and can be used to inspect all handshake messages + while the session establishment occurs. + + .. cpp:function:: void tls_log_debug(const char*) + + This callback is for exerimental purposes and currently unused. It may be + removed or modified in a future release. + +Versions from 1.11.0 to 1.11.30 did not have ``TLS::Callbacks` and instead +used independent std::functions to pass the various callback functions. +This interface is currently still included but is deprecated and will be removed +in a future release. For the documentation for this interface, please check +the docs in 1.11.30. This version of the manual only documents the new interface +added in 1.11.31. TLS Channels ---------------------------------------- @@ -80,16 +102,6 @@ available: .. cpp:class:: TLS::Channel - .. cpp:type:: std::function output_fn - - .. cpp:type:: std::function data_cb - - .. cpp:type:: std::function alert_cb - - .. cpp:type:: std::function handshake_cb - - Typedefs used in the code for the functions described above - .. cpp:function:: size_t received_data(const byte buf[], size_t buf_size) .. cpp:function:: size_t received_data(const std::vector& buf) @@ -194,10 +206,7 @@ TLS Clients .. cpp:class:: TLS::Client .. cpp:function:: Client( \ - output_fn out, \ - data_cb app_data_cb, \ - alert_cb alert_cb, \ - handshake_cb hs_cb, \ + Callbacks& callbacks, Session_Manager& session_manager, \ Credentials_Manager& creds, \ const Policy& policy, \ @@ -211,29 +220,8 @@ TLS Clients Initialize a new TLS client. The constructor will immediately initiate a new session. - The *output_fn* callback will be called with output that - should be sent to the counterparty. For instance this will be - called immediately from the constructor after the client hello - message is constructed. An implementation of *output_fn* is - allowed to defer the write (for instance if writing when the - callback occurs would block), but should eventually write the data - to the counterparty *in order*. - - The *data_cb* will be called with data sent by the counterparty - after it has been processed. The byte array and size_t represent - the plaintext value and size. - - The *alert_cb* will be called when a protocol alert is received, - commonly with a close alert during connection teardown. - - The *handshake_cb* function is called when a handshake - (either initial or renegotiation) is completed. The return value of - the callback specifies if the session should be cached for later - resumption. If the function for some reason desires to prevent the - connection from completing, it should throw an exception - (preferably a TLS::Exception, which can provide more specific alert - information to the counterparty). The :cpp:class:`TLS::Session` - provides information about the session that was just established. + The *callbacks* parameter specifies the various application callbacks + which pertain to this particular client connection. The *session_manager* is an interface for storing TLS sessions, which allows for session resumption upon reconnecting to a server. @@ -285,10 +273,7 @@ TLS Servers .. cpp:class:: TLS::Server .. cpp:function:: Server( \ - output_fn output, \ - data_cb data_cb, \ - alert_cb alert_cb, \ - handshake_cb handshake_cb, \ + Callbacks& callbacks, Session_Manager& session_manager, \ Credentials_Manager& creds, \ const Policy& policy, \ @@ -298,11 +283,11 @@ TLS Servers size_t reserved_io_buffer_size = 16*1024 \ ) -The first 8 arguments as well as the final argument +The first 5 arguments as well as the final argument *reserved_io_buffer_size*, are treated similiarly to the :ref:`client `. -The (optional) argument, *proto_chooser*, is a function called if the +The (optional) argument, *next_proto*, is a function called if the client sent the ALPN extension to negotiate an application protocol. In that case, the function should choose a protocol to use and return it. Alternately it can throw an exception to abort the @@ -312,7 +297,7 @@ should be of type `NO_APPLICATION_PROTOCOL`. The optional argument *is_datagram* specifies if this is a TLS or DTLS server; unlike clients, which know what type of protocol (TLS vs DTLS) they are negotiating from the start via the *offer_version*, servers -would not until they actually received a hello without this parameter. +would not until they actually received a client hello. Code for a TLS server using asio is in `src/cli/tls_proxy.cpp`. @@ -516,7 +501,7 @@ policy settings from a file. Values without an explicit mode use old-style CBC with HMAC encryption. Default value: "AES-256/GCM", "AES-128/GCM", "ChaCha20Poly1305", - "AES-256/CCM", "AES-128/CCM", "AES-256/CCM-8", "AES-128/CCM-8", + "AES-256/CCM", "AES-128/CCM", "AES-256/CCM(8)", "AES-128/CCM(8)", "AES-256", "AES-128" Also allowed: "Camellia-256/GCM", "Camellia-128/GCM", @@ -529,15 +514,18 @@ policy settings from a file. .. note:: - The current ChaCha20Poly1305 ciphersuites are non-standard but - as of 2015 were implemented and deployed by Google and - elsewhere. Support will be changed to using IETF standard - ChaCha20Poly1305 ciphersuites when those are defined. + Before 1.11.30 only the non-standard ChaCha20Poly1305 ciphersuite + was implemented. The RFC 7905 ciphersuites are supported in 1.11.30 + onwards. .. note:: Support for the broken RC4 cipher was removed in 1.11.17 + .. note:: + + SEED and 3DES are deprecated and will be removed in a future release. + .. cpp:function:: std::vector allowed_macs() const Returns the list of algorithms we are willing to use for @@ -577,6 +565,10 @@ policy settings from a file. Also allowed (disabled by default): "" (meaning anonymous) + .. note:: + + DSA authentication is deprecated and will be removed in a future release. + .. cpp:function:: std::vector allowed_ecc_curves() const Return a list of ECC curves we are willing to use, in order of preference. diff --git a/src/cli/tls_client.cpp b/src/cli/tls_client.cpp index e2fc1f027..082daf4ac 100644 --- a/src/cli/tls_client.cpp +++ b/src/cli/tls_client.cpp @@ -36,7 +36,7 @@ namespace Botan_CLI { -class TLS_Client final : public Command +class TLS_Client final : public Command, public Botan::TLS::Callbacks { public: TLS_Client() : Command("tls_client host --port=443 --print-certs --policy= " @@ -99,15 +99,10 @@ class TLS_Client final : public Command const std::vector protocols_to_offer = Botan::split_on("next-protocols", ','); - int sockfd = connect_to_host(host, port, use_tcp); + m_sockfd = connect_to_host(host, port, use_tcp); using namespace std::placeholders; - auto socket_write = - use_tcp ? - std::bind(stream_socket_write, sockfd, _1, _2) : - std::bind(dgram_socket_write, sockfd, _1, _2); - auto version = policy->latest_supported_version(!use_tcp); if(flag_set("tls1.0")) @@ -119,11 +114,7 @@ class TLS_Client final : public Command version = Botan::TLS::Protocol_Version::TLS_V11; } - Botan::TLS::Client client(Botan::TLS::Callbacks( - socket_write, - std::bind(&TLS_Client::process_data, this, _1, _2), - std::bind(&TLS_Client::alert_received, this, _1), - std::bind(&TLS_Client::handshake_complete, this, _1)), + Botan::TLS::Client client(*this, *session_mgr, creds, *policy, @@ -138,7 +129,7 @@ class TLS_Client final : public Command { fd_set readfds; FD_ZERO(&readfds); - FD_SET(sockfd, &readfds); + FD_SET(m_sockfd, &readfds); if(client.is_active()) { @@ -154,13 +145,13 @@ class TLS_Client final : public Command struct timeval timeout = { 1, 0 }; - ::select(sockfd + 1, &readfds, nullptr, nullptr, &timeout); + ::select(m_sockfd + 1, &readfds, nullptr, nullptr, &timeout); - if(FD_ISSET(sockfd, &readfds)) + if(FD_ISSET(m_sockfd, &readfds)) { uint8_t buf[4*1024] = { 0 }; - ssize_t got = ::read(sockfd, buf, sizeof(buf)); + ssize_t got = ::read(m_sockfd, buf, sizeof(buf)); if(got == 0) { @@ -218,7 +209,7 @@ class TLS_Client final : public Command } } - ::close(sockfd); + ::close(m_sockfd); } private: @@ -258,7 +249,7 @@ class TLS_Client final : public Command return fd; } - bool handshake_complete(const Botan::TLS::Session& session) + bool tls_session_established(const Botan::TLS::Session& session) override { output() << "Handshake complete, " << session.version().to_string() << " using " << session.ciphersuite().to_string() << "\n"; @@ -292,13 +283,13 @@ class TLS_Client final : public Command throw CLI_Error("Socket write failed errno=" + std::to_string(errno)); } - static void stream_socket_write(int sockfd, const uint8_t buf[], size_t length) + void tls_emit_data(const uint8_t buf[], size_t length) override { size_t offset = 0; while(length) { - ssize_t sent = ::send(sockfd, (const char*)buf + offset, + ssize_t sent = ::send(m_sockfd, (const char*)buf + offset, length, MSG_NOSIGNAL); if(sent == -1) @@ -314,16 +305,19 @@ class TLS_Client final : public Command } } - void alert_received(Botan::TLS::Alert alert) + void tls_alert(Botan::TLS::Alert alert) { output() << "Alert: " << alert.type_string() << "\n"; } - void process_data(const uint8_t buf[], size_t buf_size) + void tls_record_received(uint64_t seq_no, const uint8_t buf[], size_t buf_size) { for(size_t i = 0; i != buf_size; ++i) output() << buf[i]; } + + private: + int m_sockfd; }; BOTAN_REGISTER_COMMAND("tls_client", TLS_Client); diff --git a/src/cli/tls_proxy.cpp b/src/cli/tls_proxy.cpp index d52a67631..5140654de 100644 --- a/src/cli/tls_proxy.cpp +++ b/src/cli/tls_proxy.cpp @@ -60,7 +60,7 @@ void log_text_message(const char* where, const uint8_t buf[], size_t buf_len) //std::cout << where << ' ' << std::string(c, c + buf_len) << std::endl; } -class tls_proxy_session : public boost::enable_shared_from_this +class tls_proxy_session : public boost::enable_shared_from_this, public Botan::TLS::Callbacks { public: enum { readbuf_size = 4 * 1024 }; @@ -112,10 +112,7 @@ class tls_proxy_session : public boost::enable_shared_from_this 0) m_p2c_pending.insert(m_p2c_pending.end(), buf, buf + buf_len); @@ -269,7 +266,7 @@ class tls_proxy_session : public boost::enable_shared_from_this diff --git a/src/lib/tls/tls_blocking.cpp b/src/lib/tls/tls_blocking.cpp index 3910d242c..34ebc6c91 100644 --- a/src/lib/tls/tls_blocking.cpp +++ b/src/lib/tls/tls_blocking.cpp @@ -24,12 +24,13 @@ Blocking_Client::Blocking_Client(read_fn reader, const Protocol_Version& offer_version, const std::vector& next) : m_read(reader), - m_channel(TLS::Callbacks( + m_callbacks(new TLS::Compat_Callbacks( writer, std::bind(&Blocking_Client::data_cb, this, _1, _2), - std::bind(&Blocking_Client::alert_cb, this, _1), + std::function(std::bind(&Blocking_Client::alert_cb, this, _1)), std::bind(&Blocking_Client::handshake_cb, this, _1) - ), + )), + m_channel(*m_callbacks.get(), session_manager, creds, policy, @@ -38,6 +39,7 @@ Blocking_Client::Blocking_Client(read_fn reader, offer_version, next) { + printf("hi\n"); } bool Blocking_Client::handshake_cb(const Session& session) diff --git a/src/lib/tls/tls_blocking.h b/src/lib/tls/tls_blocking.h index cba44b524..0f2986710 100644 --- a/src/lib/tls/tls_blocking.h +++ b/src/lib/tls/tls_blocking.h @@ -33,6 +33,7 @@ class BOTAN_DLL Blocking_Client typedef std::function read_fn; typedef std::function write_fn; + BOTAN_DEPRECATED("Use the regular TLS::Client interface") Blocking_Client(read_fn reader, write_fn writer, Session_Manager& session_manager, @@ -93,6 +94,7 @@ class BOTAN_DLL Blocking_Client void alert_cb(const Alert& alert); read_fn m_read; + std::unique_ptr m_callbacks; TLS::Client m_channel; secure_vector m_plaintext; }; diff --git a/src/lib/tls/tls_callbacks.h b/src/lib/tls/tls_callbacks.h index 216c58ce2..db1b70693 100644 --- a/src/lib/tls/tls_callbacks.h +++ b/src/lib/tls/tls_callbacks.h @@ -1,6 +1,7 @@ /* * TLS Callbacks * (C) 2016 Matthias Gierlings +* 2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -14,33 +15,76 @@ namespace Botan { namespace TLS { -class Handshake_State; class Handshake_Message; /** -* Virtual Interface for TLS-Channel related callback handling. The default -* implementations involving std::function are only provided for compatibility -* purposes. New implementations should override the virtual member methods -* out_fn(), app_data(), alert(), handshake() and handshake_msg() instead. -* +* Encapsulates the callbacks that a TLS channel will make which are due to +* channel specific operations. */ class BOTAN_DLL Callbacks + { + public: + virtual ~Callbacks() {} + + /** + * Mandatory callback: output function + * The channel will call this with data which needs to be sent to the peer + * (eg, over a socket or some other form of IPC). The array will be overwritten + * when the function returns so a copy must be made if the data cannot be + * sent immediately. + */ + virtual void tls_emit_data(const uint8_t data[], size_t size) = 0; + + /** + * Mandatory callback: process application data + * Called when application data record is received from the peer. + * Again the array is overwritten immediately after the function returns. + * seq_no is the underlying TLS/DTLS record sequence number. + */ + virtual void tls_record_received(u64bit seq_no, const uint8_t data[], size_t size) = 0; + + /** + * Mandary callback: alert received + * Called when an alert is received from the peer + * If fatal, the connection is closing. If not fatal, the connection may + * still be closing (depending on the error and the peer). + */ + virtual void tls_alert(Alert alert) = 0; + + /** + * Mandatory callback: session established + * Called when a session is established. Throw an exception to abort + * the connection. Return false to prevent the session from being cached. + * Return true to cache the session in the configured session manager. + */ + virtual bool tls_session_established(const Session& session) = 0; + + /** + * Optional callback: inspect handshake message + */ + virtual void tls_inspect_handshake_msg(const Handshake_Message&) {} + + /** + * Optional callback: debug logging. (not currently used) + */ + virtual bool tls_log_debug(const char*) { return false; } + }; + +/** +* TLS::Callbacks using std::function for compatability with the old API signatures. +* This type is only provided for backward compatibility. +* New implementations should derive from TLS::Callbacks instead. +*/ +class BOTAN_DLL Compat_Callbacks final : public Callbacks { public: typedef std::function output_fn; typedef std::function data_cb; - typedef std::function alert_cb; + typedef std::function alert_cb; typedef std::function handshake_cb; typedef std::function handshake_msg_cb; /** - * DEPRECATED: This constructor is only provided for backward - * compatibility. New implementations should override the - * virtual member methods out_fn(), app_data(), alert(), - * handshake() and handshake_msg() and use the default constructor - * Callbacks(). - * - * 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 @@ -49,48 +93,50 @@ class BOTAN_DLL Callbacks * * @param handshake_cb is called when a handshake is completed */ - BOTAN_DEPRECATED("Use TLS::Callbacks() (virtual interface).") - Callbacks(output_fn out, data_cb app_data_cb, alert_cb alert_cb, - handshake_cb hs_cb, handshake_msg_cb hs_msg_cb = nullptr) + BOTAN_DEPRECATED("Use TLS::Callbacks (virtual interface).") + Compat_Callbacks(output_fn out, data_cb app_data_cb, alert_cb alert_cb, + handshake_cb hs_cb, handshake_msg_cb hs_msg_cb = nullptr) : 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) {} + m_alert_cb(std::bind(alert_cb, std::placeholders::_1, nullptr, 0)), + m_hs_cb(hs_cb), m_hs_msg_cb(hs_msg_cb) {} - Callbacks() - : m_output_function(nullptr), m_app_data_cb(nullptr), - m_alert_cb(nullptr), m_hs_cb(nullptr), m_hs_msg_cb(nullptr) {} - - - virtual ~Callbacks() {} + BOTAN_DEPRECATED("Use TLS::Callbacks (virtual interface).") + Compat_Callbacks(output_fn out, data_cb app_data_cb, + std::function alert_cb, + handshake_cb hs_cb, handshake_msg_cb hs_msg_cb = nullptr) + : 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) {} - virtual void out_fn(const byte data[], size_t size) const + void tls_emit_data(const byte data[], size_t size) override { BOTAN_ASSERT(m_output_function != nullptr, "Invalid TLS output function callback."); m_output_function(data, size); } - virtual void app_data(const byte data[], size_t size) const + void tls_record_received(u64bit /*seq_no*/, const byte data[], size_t size) override { BOTAN_ASSERT(m_app_data_cb != nullptr, "Invalid TLS app data callback."); m_app_data_cb(data, size); } - virtual void alert(Alert alert) const + void tls_alert(Alert alert) override { BOTAN_ASSERT(m_alert_cb != nullptr, "Invalid TLS alert callback."); m_alert_cb(alert); } - virtual bool handshake(const Session& session) const + bool tls_session_established(const Session& session) override { BOTAN_ASSERT(m_hs_cb != nullptr, "Invalid TLS handshake callback."); return m_hs_cb(session); } - virtual void handshake_msg(const Handshake_Message& hmsg) const + void tls_inspect_handshake_msg(const Handshake_Message& hmsg) override { // The handshake message callback is optional so we can // not assume it has been set. @@ -100,7 +146,7 @@ class BOTAN_DLL Callbacks private: const output_fn m_output_function; const data_cb m_app_data_cb; - const alert_cb m_alert_cb; + const std::function m_alert_cb; const handshake_cb m_hs_cb; const handshake_msg_cb m_hs_msg_cb; }; diff --git a/src/lib/tls/tls_channel.cpp b/src/lib/tls/tls_channel.cpp index b78796536..5f882af64 100644 --- a/src/lib/tls/tls_channel.cpp +++ b/src/lib/tls/tls_channel.cpp @@ -1,6 +1,6 @@ /* * TLS Channels -* (C) 2011,2012,2014,2015 Jack Lloyd +* (C) 2011,2012,2014,2015,2016 Jack Lloyd * 2016 Matthias Gierlings * * Botan is released under the Simplified BSD License (see license.txt) @@ -21,7 +21,7 @@ namespace TLS { size_t TLS::Channel::IO_BUF_DEFAULT_SIZE = 10*1024; -Channel::Channel(const Callbacks& callbacks, +Channel::Channel(Callbacks& callbacks, Session_Manager& session_manager, RandomNumberGenerator& rng, const Policy& policy, @@ -47,7 +47,8 @@ Channel::Channel(output_fn out, bool is_datagram, size_t io_buf_sz) : m_is_datagram(is_datagram), - m_callbacks(Callbacks(out, app_data_cb, alert_cb, hs_cb, hs_msg_cb)), + m_compat_callbacks(new Compat_Callbacks(out, app_data_cb, alert_cb, hs_cb, hs_msg_cb)), + m_callbacks(*m_compat_callbacks.get()), m_session_manager(session_manager), m_policy(policy), m_rng(rng) @@ -319,15 +320,15 @@ size_t Channel::received_data(const byte input[], size_t input_size) if(record_type == HANDSHAKE || record_type == CHANGE_CIPHER_SPEC) { - process_handshake_ccs(record_data, record_sequence, record_type, record_version); + process_handshake_ccs(record_data, record_sequence, record_type, record_version); } else if(record_type == APPLICATION_DATA) { - process_application_data(record_data); + process_application_data(record_sequence, record_data); } else if(record_type == ALERT) { - process_alert(record_data); + process_alert(record_data); } else if(record_type != NO_RECORD) throw Unexpected_Message("Unexpected record type " + @@ -359,10 +360,10 @@ size_t Channel::received_data(const byte input[], size_t input_size) } } -void Channel::process_handshake_ccs(secure_vector& record, - u64bit& record_sequence, - Record_Type& record_type, - Protocol_Version& record_version) +void Channel::process_handshake_ccs(const secure_vector& record, + u64bit record_sequence, + Record_Type record_type, + Protocol_Version record_version) { if(!m_pending_state) { @@ -422,7 +423,7 @@ void Channel::process_handshake_ccs(secure_vector& record, } } -void Channel::process_application_data(secure_vector& record) +void Channel::process_application_data(u64bit seq_no, const secure_vector& record) { if(!active_state()) throw Unexpected_Message("Application data before handshake done"); @@ -433,17 +434,17 @@ void Channel::process_application_data(secure_vector& record) * following record. Avoid spurious callbacks. */ if(record.size() > 0) - m_callbacks.app_data(record.data(), record.size()); + callbacks().tls_record_received(seq_no, record.data(), record.size()); } -void Channel::process_alert(secure_vector& record) +void Channel::process_alert(const secure_vector& record) { Alert alert_msg(record); if(alert_msg.type() == Alert::NO_RENEGOTIATION) m_pending_state.reset(); - m_callbacks.alert(alert_msg); + callbacks().tls_alert(alert_msg); if(alert_msg.is_fatal()) { @@ -478,7 +479,7 @@ void Channel::write_record(Connection_Cipher_State* cipher_state, u16bit epoch, cipher_state, m_rng); - m_callbacks.out_fn(m_writebuf.data(), m_writebuf.size()); + callbacks().tls_emit_data(m_writebuf.data(), m_writebuf.size()); } void Channel::send_record_array(u16bit epoch, byte type, const byte input[], size_t length) diff --git a/src/lib/tls/tls_channel.h b/src/lib/tls/tls_channel.h index 7c59e1d6f..073af760f 100644 --- a/src/lib/tls/tls_channel.h +++ b/src/lib/tls/tls_channel.h @@ -36,12 +36,12 @@ class BOTAN_DLL Channel public: typedef std::function output_fn; typedef std::function data_cb; - typedef std::function alert_cb; + typedef std::function alert_cb; typedef std::function handshake_cb; typedef std::function handshake_msg_cb; static size_t IO_BUF_DEFAULT_SIZE; - Channel(const Callbacks& callbacks, + Channel(Callbacks& callbacks, Session_Manager& session_manager, RandomNumberGenerator& rng, const Policy& policy, @@ -215,9 +215,9 @@ class BOTAN_DLL Channel const Policy& policy() const { return m_policy; } - bool save_session(const Session& session) const { return m_callbacks.handshake(session); } + bool save_session(const Session& session) const { return callbacks().tls_session_established(session); } - Callbacks get_callbacks() const { return m_callbacks; } + Callbacks& callbacks() const { return m_callbacks; } private: void init(size_t io_buf_sze); @@ -245,19 +245,20 @@ class BOTAN_DLL Channel 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& record, - u64bit& record_sequence, - Record_Type& record_type, - Protocol_Version& record_version); + void process_handshake_ccs(const secure_vector& record, + u64bit record_sequence, + Record_Type record_type, + Protocol_Version record_version); - void process_application_data(secure_vector& record); + void process_application_data(u64bit req_no, const secure_vector& record); - void process_alert(secure_vector& record); + void process_alert(const secure_vector& record); bool m_is_datagram; /* callbacks */ - Callbacks m_callbacks; + std::unique_ptr m_compat_callbacks; + Callbacks& m_callbacks; /* external state */ Session_Manager& m_session_manager; diff --git a/src/lib/tls/tls_client.cpp b/src/lib/tls/tls_client.cpp index ab7beddbd..f77521c03 100644 --- a/src/lib/tls/tls_client.cpp +++ b/src/lib/tls/tls_client.cpp @@ -24,7 +24,7 @@ class Client_Handshake_State : public Handshake_State public: // using Handshake_State::Handshake_State; - Client_Handshake_State(Handshake_IO* io, handshake_msg_cb cb) : Handshake_State(io, cb) {} + Client_Handshake_State(Handshake_IO* io, Callbacks& cb) : Handshake_State(io, cb) {} const Public_Key& get_server_public_Key() const { @@ -43,7 +43,7 @@ class Client_Handshake_State : public Handshake_State /* * TLS Client Constructor */ -Client::Client(const Callbacks& callbacks, +Client::Client(Callbacks& callbacks, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, @@ -112,10 +112,7 @@ void Client::init(const Protocol_Version& protocol_version, Handshake_State* Client::new_handshake_state(Handshake_IO* io) { - return new Client_Handshake_State(io, - std::bind(&TLS::Callbacks::handshake_msg, - get_callbacks(), - std::placeholders::_1)); + return new Client_Handshake_State(io, callbacks()); } std::vector diff --git a/src/lib/tls/tls_client.h b/src/lib/tls/tls_client.h index 6452294cd..09af053af 100644 --- a/src/lib/tls/tls_client.h +++ b/src/lib/tls/tls_client.h @@ -23,6 +23,7 @@ namespace TLS { class BOTAN_DLL Client final : public Channel { public: + /** * Set up a new TLS client session * @@ -48,7 +49,51 @@ class BOTAN_DLL Client final : public Channel * be preallocated for the read and write buffers. Smaller * values just mean reallocations and copies are more likely. */ + Client(Callbacks& callbacks, + Session_Manager& session_manager, + Credentials_Manager& creds, + const Policy& policy, + RandomNumberGenerator& rng, + const Server_Information& server_info = Server_Information(), + const Protocol_Version& offer_version = Protocol_Version::latest_tls_version(), + const std::vector& next_protocols = {}, + size_t reserved_io_buffer_size = TLS::Client::IO_BUF_DEFAULT_SIZE + ); + /** + * DEPRECATED. This constructor is only provided for backward + * compatibility and should not be used in new code. + * + * Set up a new TLS client session + * + * @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 + * + * @param session_manager manages session state + * + * @param creds manages application/user credentials + * + * @param policy specifies other connection policy information + * + * @param rng a random number generator + * + * @param server_info is identifying information about the TLS server + * + * @param offer_version specifies which version we will offer + * to the TLS server. + * + * @param next_protocols specifies protocols to advertise with ALPN + * + * @param reserved_io_buffer_size This many bytes of memory will + * be preallocated for the read and write buffers. Smaller + * values just mean reallocations and copies are more likely. + */ + BOTAN_DEPRECATED("Use TLS::Client(TLS::Callbacks ...)") Client(output_fn out, data_cb app_data_cb, alert_cb alert_cb, @@ -82,18 +127,6 @@ class BOTAN_DLL Client final : public Channel const std::vector& next_protocols = {} ); - - Client(const Callbacks& callbacks, - Session_Manager& session_manager, - Credentials_Manager& creds, - const Policy& policy, - RandomNumberGenerator& rng, - const Server_Information& server_info = Server_Information(), - const Protocol_Version& offer_version = Protocol_Version::latest_tls_version(), - const std::vector& next_protocols = {}, - size_t reserved_io_buffer_size = TLS::Client::IO_BUF_DEFAULT_SIZE - ); - const std::string& application_protocol() const { return m_application_protocol; } private: void init(const Protocol_Version& protocol_version, diff --git a/src/lib/tls/tls_handshake_state.cpp b/src/lib/tls/tls_handshake_state.cpp index afc32ba87..71cacdabd 100644 --- a/src/lib/tls/tls_handshake_state.cpp +++ b/src/lib/tls/tls_handshake_state.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace Botan { @@ -174,8 +175,8 @@ std::string handshake_mask_to_string(u32bit mask) /* * Initialize the SSL/TLS Handshake State */ -Handshake_State::Handshake_State(Handshake_IO* io, handshake_msg_cb cb) : - m_msg_callback(cb), +Handshake_State::Handshake_State(Handshake_IO* io, Callbacks& cb) : + m_callbacks(cb), m_handshake_io(io), m_version(m_handshake_io->initial_record_version()) { @@ -183,6 +184,11 @@ Handshake_State::Handshake_State(Handshake_IO* io, handshake_msg_cb cb) : Handshake_State::~Handshake_State() {} +void Handshake_State::note_message(const Handshake_Message& msg) + { + m_callbacks.tls_inspect_handshake_msg(msg); + } + void Handshake_State::hello_verify_request(const Hello_Verify_Request& hello_verify) { note_message(hello_verify); diff --git a/src/lib/tls/tls_handshake_state.h b/src/lib/tls/tls_handshake_state.h index 2943a8637..bdec10d14 100644 --- a/src/lib/tls/tls_handshake_state.h +++ b/src/lib/tls/tls_handshake_state.h @@ -24,6 +24,7 @@ class KDF; namespace TLS { +class Callbacks; class Policy; class Hello_Verify_Request; @@ -45,9 +46,7 @@ class Finished; class Handshake_State { public: - typedef std::function handshake_msg_cb; - - Handshake_State(Handshake_IO* io, handshake_msg_cb cb); + Handshake_State(Handshake_IO* io, Callbacks& callbacks); virtual ~Handshake_State(); @@ -164,15 +163,10 @@ class Handshake_State const Handshake_Hash& hash() const { return m_handshake_hash; } - void note_message(const Handshake_Message& msg) - { - if(m_msg_callback) - m_msg_callback(msg); - } - + void note_message(const Handshake_Message& msg); private: - handshake_msg_cb m_msg_callback; + Callbacks& m_callbacks; std::unique_ptr m_handshake_io; diff --git a/src/lib/tls/tls_record.h b/src/lib/tls/tls_record.h index 53e447af6..c16b919b5 100644 --- a/src/lib/tls/tls_record.h +++ b/src/lib/tls/tls_record.h @@ -102,10 +102,6 @@ class Record m_type(type), m_size(data.size()) {}; secure_vector& get_data() { return m_data; } - void set_data(secure_vector data) - { - m_data.swap(data); - } Protocol_Version* get_protocol_version() { return m_protocol_version; } diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp index 96af3cc90..5eccec2a7 100644 --- a/src/lib/tls/tls_server.cpp +++ b/src/lib/tls/tls_server.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -17,9 +16,34 @@ namespace Botan { namespace TLS { -namespace { +class Server_Handshake_State : public Handshake_State + { + public: + Server_Handshake_State(Handshake_IO* io, Callbacks& cb) + : Handshake_State(io, cb) {} + + Private_Key* server_rsa_kex_key() { return m_server_rsa_kex_key; } + void set_server_rsa_kex_key(Private_Key* key) + { m_server_rsa_kex_key = key; } + + bool allow_session_resumption() const + { return m_allow_session_resumption; } + void set_allow_session_resumption(bool allow_session_resumption) + { m_allow_session_resumption = allow_session_resumption; } + + private: + // Used by the server only, in case of RSA key exchange. Not owned + Private_Key* m_server_rsa_kex_key = nullptr; + /* + * Used by the server to know if resumption should be allowed on + * a server-initiated renegotiation + */ + bool m_allow_session_resumption = true; + }; + +namespace { bool check_for_resume(Session& session_info, Session_Manager& session_manager, @@ -213,7 +237,7 @@ get_server_certs(const std::string& hostname, /* * TLS Server Constructor */ -Server::Server(const Callbacks& callbacks, +Server::Server(Callbacks& callbacks, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, @@ -268,11 +292,7 @@ Server::Server(output_fn output, Handshake_State* Server::new_handshake_state(Handshake_IO* io) { - std::unique_ptr state( - new Server_Handshake_State(io, - std::bind(&TLS::Callbacks::handshake_msg, - get_callbacks(), - std::placeholders::_1))); + std::unique_ptr state(new Server_Handshake_State(io, callbacks())); state->set_expected_next(CLIENT_HELLO); return state.release(); diff --git a/src/lib/tls/tls_server.h b/src/lib/tls/tls_server.h index c0960a66e..508dde440 100644 --- a/src/lib/tls/tls_server.h +++ b/src/lib/tls/tls_server.h @@ -30,8 +30,29 @@ class BOTAN_DLL Server final : public Channel /** * Server initialization + * + * @param callbacks contains a set of callback function references + * required by the TLS client. + * + * @param session_manager manages session state + * + * @param creds manages application/user credentials + * + * @param policy specifies other connection policy information + * + * @param rng a random number generator + * + * @param next_proto is called with client's ALPN protocol list + * and returns chosen protocol. + * + * @param is_datagram set to true if this server should expect DTLS + * connections. Otherwise TLS connections are expected. + * + * @param reserved_io_buffer_size This many bytes of memory will + * be preallocated for the read and write buffers. Smaller + * values just mean reallocations and copies are more likely. */ - Server(const Callbacks& callbacks, + Server(Callbacks& callbacks, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, diff --git a/src/lib/tls/tls_server_handshake_state.h b/src/lib/tls/tls_server_handshake_state.h deleted file mode 100644 index c65cade96..000000000 --- a/src/lib/tls/tls_server_handshake_state.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -* TLS Server -* (C) 2004-2011,2012,2016 Jack Lloyd -* 2016 Matthias Gierlings -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_TLS_SERVER_HANDSHAKE_STATE_H__ -#define BOTAN_TLS_SERVER_HANDSHAKE_STATE_H__ - -#include -namespace Botan { - -namespace TLS { - -class Server_Handshake_State : public Handshake_State - { - public: - Server_Handshake_State(Handshake_IO* io, handshake_msg_cb cb) - : Handshake_State(io, cb) {} - - Private_Key* server_rsa_kex_key() { return m_server_rsa_kex_key; } - void set_server_rsa_kex_key(Private_Key* key) - { m_server_rsa_kex_key = key; } - - bool allow_session_resumption() const - { return m_allow_session_resumption; } - void set_allow_session_resumption(bool allow_session_resumption) - { m_allow_session_resumption = allow_session_resumption; } - - - private: - // Used by the server only, in case of RSA key exchange. Not owned - Private_Key* m_server_rsa_kex_key = nullptr; - - /* - * Used by the server to know if resumption should be allowed on - * a server-initiated renegotiation - */ - bool m_allow_session_resumption = true; - }; - -} - -} - -#endif diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index 150ed2794..2797e7d21 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -166,6 +166,10 @@ void print_alert(Botan::TLS::Alert) { } +void alert_cb_with_data(Botan::TLS::Alert, const byte[], size_t) + { + } + Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, Botan::Credentials_Manager& creds, Botan::TLS::Policy& policy) @@ -219,27 +223,31 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, { std::vector c2s_traffic, s2c_traffic, client_recv, server_recv, client_sent, server_sent; + std::unique_ptr server_cb(new Botan::TLS::Compat_Callbacks( + queue_inserter(s2c_traffic), + queue_inserter(server_recv), + std::function(alert_cb_with_data), + handshake_complete)); + // TLS::Server object constructed by new constructor using virtual callback interface. std::unique_ptr server( - new Botan::TLS::Server(Botan::TLS::Callbacks( - queue_inserter(s2c_traffic), - queue_inserter(server_recv), - print_alert, - handshake_complete), - server_sessions, - creds, - policy, - rng, - next_protocol_chooser, - false)); + new Botan::TLS::Server(*server_cb, + server_sessions, + creds, + policy, + rng, + next_protocol_chooser, + false)); + + std::unique_ptr client_cb(new Botan::TLS::Compat_Callbacks( + queue_inserter(c2s_traffic), + queue_inserter(client_recv), + std::function(alert_cb_with_data), + handshake_complete)); // TLS::Client object constructed by new constructor using virtual callback interface. std::unique_ptr client( - new Botan::TLS::Client(Botan::TLS::Callbacks( - queue_inserter(c2s_traffic), - queue_inserter(client_recv), - print_alert, - handshake_complete), + new Botan::TLS::Client(*client_cb, client_sessions, creds, policy, @@ -255,11 +263,18 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, { if(ctor_sel == 1) { + c2s_traffic.clear(); + s2c_traffic.clear(); + server_recv.clear(); + client_recv.clear(); + client_sent.clear(); + server_sent.clear(); + // TLS::Server object constructed by legacy constructor. - server = std::unique_ptr( + server.reset( new Botan::TLS::Server(queue_inserter(s2c_traffic), queue_inserter(server_recv), - print_alert, + alert_cb_with_data, handshake_complete, server_sessions, creds, @@ -269,10 +284,10 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, false)); // TLS::Client object constructed by legacy constructor. - std::unique_ptr client( + client.reset( new Botan::TLS::Client(queue_inserter(c2s_traffic), queue_inserter(client_recv), - print_alert, + alert_cb_with_data, handshake_complete, client_sessions, creds, @@ -485,13 +500,21 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, { std::vector c2s_traffic, s2c_traffic, client_recv, server_recv, client_sent, server_sent; + std::unique_ptr server_cb(new Botan::TLS::Compat_Callbacks( + queue_inserter(s2c_traffic), + queue_inserter(server_recv), + std::function(print_alert), + handshake_complete)); + + std::unique_ptr client_cb(new Botan::TLS::Compat_Callbacks( + queue_inserter(c2s_traffic), + queue_inserter(client_recv), + std::function(print_alert), + handshake_complete)); + // TLS::Server object constructed by new constructor using virtual callback interface. std::unique_ptr server( - new Botan::TLS::Server(Botan::TLS::Callbacks( - queue_inserter(s2c_traffic), - queue_inserter(server_recv), - print_alert, - handshake_complete), + new Botan::TLS::Server(*server_cb, server_sessions, creds, policy, @@ -501,11 +524,7 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, // TLS::Client object constructed by new constructor using virtual callback interface. std::unique_ptr client( - new Botan::TLS::Client(Botan::TLS::Callbacks( - queue_inserter(c2s_traffic), - queue_inserter(client_recv), - print_alert, - handshake_complete), + new Botan::TLS::Client(*client_cb, client_sessions, creds, policy, @@ -521,11 +540,17 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, { if(ctor_sel == 1) { + c2s_traffic.clear(); + s2c_traffic.clear(); + server_recv.clear(); + client_recv.clear(); + client_sent.clear(); + server_sent.clear(); // TLS::Server object constructed by legacy constructor. - server = std::unique_ptr( + server.reset( new Botan::TLS::Server(queue_inserter(s2c_traffic), queue_inserter(server_recv), - print_alert, + alert_cb_with_data, handshake_complete, server_sessions, creds, @@ -535,10 +560,10 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, true)); // TLS::Client object constructed by legacy constructor. - std::unique_ptr client( + client.reset( new Botan::TLS::Client(queue_inserter(c2s_traffic), queue_inserter(client_recv), - print_alert, + alert_cb_with_data, handshake_complete, client_sessions, creds, -- cgit v1.2.3 From dd5cda336851212e200f3b62cf9c89a6984725c3 Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Tue, 16 Aug 2016 15:45:10 -0400 Subject: Add a Callbacks function for ALPN --- doc/manual/tls.rst | 44 ++++++++++++++++++++++++++++++-------------- src/lib/tls/tls_callbacks.h | 35 +++++++++++++++++++++++++++++++---- src/lib/tls/tls_server.cpp | 16 +++++++++++----- src/lib/tls/tls_server.h | 7 ++----- src/tests/unit_tls.cpp | 10 ++++++---- 5 files changed, 80 insertions(+), 32 deletions(-) (limited to 'src/tests/unit_tls.cpp') diff --git a/doc/manual/tls.rst b/doc/manual/tls.rst index 7210fc092..6c1ca42f2 100644 --- a/doc/manual/tls.rst +++ b/doc/manual/tls.rst @@ -38,17 +38,21 @@ information about the connection. .. cpp:function:: void tls_emit_data(const byte data[], size_t data_len) - The TLS stack requests that all bytes of *data* be queued up to send to the + Mandatory. The TLS stack requests that all bytes of *data* be queued up to send to the counterparty. After this function returns, the buffer containing *data* will be overwritten, so a copy of the input must be made if the callback cannot send the data immediately. - The write can be deferred but for TLS all writes must occur *in order*. - For DTLS this is not strictly required, but is still recommended. + As an example you could ``send`` to perform a blocking write on a socket, + or append the data to a queue managed by your application, and initiate + an asyncronous write. + + For TLS all writes must occur *in the order requested*. + For DTLS this ordering is not strictly required, but is still recommended. .. cpp:function:: void tls_record_received(uint64_t rec_no, const byte data[], size_t data_len) - Called once for each application_data record which is received, with the + Mandatory. Called once for each application_data record which is received, with the matching (TLS level) record sequence number. Currently empty records are ignored and do not instigate a callback, @@ -57,15 +61,21 @@ information about the connection. As with ``tls_emit_data``, the array will be overwritten sometime after the callback returns, so a copy should be made if needed. + For TLS the record number will always increase. + + For DTLS, it is possible to receive records with the `rec_no` field + field out of order or repeated. It is even possible (from a malicious or + faulty peer) to receive multiple copies of a single record with differing plaintexts. + .. cpp:function:: void tls_alert(Alert alert) - Called when an alert is received from the peer. Note that alerts + Mandatory. Called when an alert is received from the peer. Note that alerts received before the handshake is complete are not authenticated and could have been inserted by a MITM attacker. .. cpp:function:: bool tls_session_established(const TLS::Session& session) - Called whenever a negotiation completes. This can happen more + Mandatory. Called whenever a negotiation completes. This can happen more than once on any connection, if renegotiation occurs. The *session* parameter provides information about the session which was just established. @@ -76,6 +86,13 @@ information about the connection. exception which will send a close message to the counterparty and reset the connection state. + .. cpp:function:: std::string tls_server_choose_app_protocol(const std::vector& client_protos) + + Optional. Called by the server when a client includes a list of protocols in the ALPN extension. + The server then choose which protocol to use, or "" to disable sending any ALPN response. + The default implementation returns the empty string all of the time, effectively disabling + ALPN responses. + .. cpp:function:: void tls_inspect_handshake_msg(const Handshake_Message&) This callback is optional, and can be used to inspect all handshake messages @@ -90,7 +107,7 @@ Versions from 1.11.0 to 1.11.30 did not have ``TLS::Callbacks` and instead used independent std::functions to pass the various callback functions. This interface is currently still included but is deprecated and will be removed in a future release. For the documentation for this interface, please check -the docs in 1.11.30. This version of the manual only documents the new interface +the docs for 1.11.30. This version of the manual only documents the new interface added in 1.11.31. TLS Channels @@ -278,7 +295,6 @@ TLS Servers Credentials_Manager& creds, \ const Policy& policy, \ RandomNumberGenerator& rng, \ - next_protocol_fn next_proto = next_protocol_fn(), \ bool is_datagram = false, \ size_t reserved_io_buffer_size = 16*1024 \ ) @@ -287,12 +303,12 @@ The first 5 arguments as well as the final argument *reserved_io_buffer_size*, are treated similiarly to the :ref:`client `. -The (optional) argument, *next_proto*, is a function called if the -client sent the ALPN extension to negotiate an application -protocol. In that case, the function should choose a protocol to use -and return it. Alternately it can throw an exception to abort the -exchange; the ALPN specification says that if this occurs the alert -should be of type `NO_APPLICATION_PROTOCOL`. +If a client sends the ALPN extension, the ``callbacks`` function +``tls_server_choose_app_protocol`` will be called and the result +sent back to the client. If the empty string is returned, the server +will not send an ALPN response. The function can also throw an exception +to abort the handshake entirely, the ALPN specification says that if this +occurs the alert should be of type `NO_APPLICATION_PROTOCOL`. The optional argument *is_datagram* specifies if this is a TLS or DTLS server; unlike clients, which know what type of protocol (TLS vs DTLS) diff --git a/src/lib/tls/tls_callbacks.h b/src/lib/tls/tls_callbacks.h index db1b70693..5c7b21a99 100644 --- a/src/lib/tls/tls_callbacks.h +++ b/src/lib/tls/tls_callbacks.h @@ -61,9 +61,25 @@ class BOTAN_DLL Callbacks /** * Optional callback: inspect handshake message + * Throw an exception to abort the handshake. */ virtual void tls_inspect_handshake_msg(const Handshake_Message&) {} + /** + * Optional callback for server: choose ALPN protocol + * ALPN (RFC 7301) works by the client sending a list of application + * protocols it is willing to negotiate. The server then selects which + * protocol to use, which is not necessarily even on the list that + * the client sent. + * + * If the empty string is returned from this function the server will + * just ignore the client ALPN extension. + */ + virtual std::string tls_server_choose_app_protocol(const std::vector& client_protos) + { + return ""; + } + /** * Optional callback: debug logging. (not currently used) */ @@ -83,6 +99,7 @@ class BOTAN_DLL Compat_Callbacks final : public Callbacks typedef std::function alert_cb; typedef std::function handshake_cb; typedef std::function handshake_msg_cb; + typedef std::function)> next_protocol_fn; /** * @param output_fn is called with data for the outbound socket @@ -95,18 +112,21 @@ class BOTAN_DLL Compat_Callbacks final : public Callbacks */ BOTAN_DEPRECATED("Use TLS::Callbacks (virtual interface).") Compat_Callbacks(output_fn out, data_cb app_data_cb, alert_cb alert_cb, - handshake_cb hs_cb, handshake_msg_cb hs_msg_cb = nullptr) + handshake_cb hs_cb, handshake_msg_cb hs_msg_cb = nullptr, + next_protocol_fn next_proto = nullptr) : m_output_function(out), m_app_data_cb(app_data_cb), m_alert_cb(std::bind(alert_cb, std::placeholders::_1, nullptr, 0)), - m_hs_cb(hs_cb), m_hs_msg_cb(hs_msg_cb) {} + m_hs_cb(hs_cb), m_hs_msg_cb(hs_msg_cb), m_next_proto(next_proto) {} BOTAN_DEPRECATED("Use TLS::Callbacks (virtual interface).") Compat_Callbacks(output_fn out, data_cb app_data_cb, std::function alert_cb, - handshake_cb hs_cb, handshake_msg_cb hs_msg_cb = nullptr) + handshake_cb hs_cb, + handshake_msg_cb hs_msg_cb = nullptr, + next_protocol_fn next_proto = nullptr) : 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) {} + m_hs_cb(hs_cb), m_hs_msg_cb(hs_msg_cb), m_next_proto(next_proto) {} void tls_emit_data(const byte data[], size_t size) override { @@ -136,6 +156,12 @@ class BOTAN_DLL Compat_Callbacks final : public Callbacks return m_hs_cb(session); } + std::string tls_server_choose_app_protocol(const std::vector& client_protos) override + { + if(m_next_proto != nullptr) { return m_next_proto(client_protos); } + return ""; + } + void tls_inspect_handshake_msg(const Handshake_Message& hmsg) override { // The handshake message callback is optional so we can @@ -149,6 +175,7 @@ class BOTAN_DLL Compat_Callbacks final : public Callbacks const std::function m_alert_cb; const handshake_cb m_hs_cb; const handshake_msg_cb m_hs_msg_cb; + const next_protocol_fn m_next_proto; }; } diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp index 5eccec2a7..2e546eab1 100644 --- a/src/lib/tls/tls_server.cpp +++ b/src/lib/tls/tls_server.cpp @@ -242,13 +242,11 @@ Server::Server(Callbacks& callbacks, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, - next_protocol_fn next_proto, bool is_datagram, size_t io_buf_sz) : Channel(callbacks, session_manager, rng, policy, is_datagram, io_buf_sz), - m_creds(creds), - m_choose_next_protocol(next_proto) + m_creds(creds) { } @@ -419,8 +417,16 @@ void Server::process_client_hello_msg(const Handshake_State* active_state, catch(...) {} m_next_protocol = ""; - if(m_choose_next_protocol && pending_state.client_hello()->supports_alpn()) - m_next_protocol = m_choose_next_protocol(pending_state.client_hello()->next_protocols()); + if(pending_state.client_hello()->supports_alpn()) + { + m_next_protocol = callbacks().tls_server_choose_app_protocol(pending_state.client_hello()->next_protocols()); + + // if the callback return was empty, fall back to the (deprecated) std::function + if(m_next_protocol.empty() && m_choose_next_protocol) + { + m_next_protocol = m_choose_next_protocol(pending_state.client_hello()->next_protocols()); + } + } if(resuming) { diff --git a/src/lib/tls/tls_server.h b/src/lib/tls/tls_server.h index 508dde440..051eda445 100644 --- a/src/lib/tls/tls_server.h +++ b/src/lib/tls/tls_server.h @@ -42,9 +42,6 @@ class BOTAN_DLL Server final : public Channel * * @param rng a random number generator * - * @param next_proto is called with client's ALPN protocol list - * and returns chosen protocol. - * * @param is_datagram set to true if this server should expect DTLS * connections. Otherwise TLS connections are expected. * @@ -57,7 +54,6 @@ class BOTAN_DLL Server final : public Channel Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, - next_protocol_fn next_proto = next_protocol_fn(), bool is_datagram = false, size_t reserved_io_buffer_size = TLS::Server::IO_BUF_DEFAULT_SIZE ); @@ -148,9 +144,10 @@ class BOTAN_DLL Server final : public Channel Handshake_State* new_handshake_state(Handshake_IO* io) override; Credentials_Manager& m_creds; + std::string m_next_protocol; + // Set by deprecated constructor, Server calls both this fn and Callbacks version next_protocol_fn m_choose_next_protocol; - std::string m_next_protocol; }; } diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index 2797e7d21..f0caa4aef 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -227,7 +227,9 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, queue_inserter(s2c_traffic), queue_inserter(server_recv), std::function(alert_cb_with_data), - handshake_complete)); + handshake_complete, + nullptr, + next_protocol_chooser)); // TLS::Server object constructed by new constructor using virtual callback interface. std::unique_ptr server( @@ -236,7 +238,6 @@ Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version, creds, policy, rng, - next_protocol_chooser, false)); std::unique_ptr client_cb(new Botan::TLS::Compat_Callbacks( @@ -504,7 +505,9 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, queue_inserter(s2c_traffic), queue_inserter(server_recv), std::function(print_alert), - handshake_complete)); + handshake_complete, + nullptr, + next_protocol_chooser)); std::unique_ptr client_cb(new Botan::TLS::Compat_Callbacks( queue_inserter(c2s_traffic), @@ -519,7 +522,6 @@ Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version, creds, policy, rng, - next_protocol_chooser, true)); // TLS::Client object constructed by new constructor using virtual callback interface. -- cgit v1.2.3