diff options
-rw-r--r-- | src/tls/info.txt | 1 | ||||
-rw-r--r-- | src/tls/rec_wri.cpp | 144 | ||||
-rw-r--r-- | src/tls/tls_channel.cpp | 105 | ||||
-rw-r--r-- | src/tls/tls_channel.h | 12 | ||||
-rw-r--r-- | src/tls/tls_client.cpp | 3 | ||||
-rw-r--r-- | src/tls/tls_record.h | 46 |
6 files changed, 101 insertions, 210 deletions
diff --git a/src/tls/info.txt b/src/tls/info.txt index 376f2b21c..0c31b268b 100644 --- a/src/tls/info.txt +++ b/src/tls/info.txt @@ -47,7 +47,6 @@ msg_server_hello.cpp msg_server_kex.cpp msg_session_ticket.cpp rec_read.cpp -rec_wri.cpp tls_alert.cpp tls_channel.cpp tls_ciphersuite.cpp diff --git a/src/tls/rec_wri.cpp b/src/tls/rec_wri.cpp deleted file mode 100644 index 33edbfb2f..000000000 --- a/src/tls/rec_wri.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* -* TLS Record Writing -* (C) 2004-2012 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include <botan/tls_record.h> -#include <botan/tls_magic.h> -#include <botan/internal/tls_session_key.h> -#include <botan/internal/rounding.h> - -namespace Botan { - -namespace TLS { - -/* -* Record_Writer Constructor -*/ -Record_Writer::Record_Writer(std::function<void (const byte[], size_t)> out, - RandomNumberGenerator& rng) : - m_output_fn(out), - m_writebuf(TLS_HEADER_SIZE + MAX_CIPHERTEXT_SIZE), - m_rng(rng) - { - reset(); - } - -void Record_Writer::set_maximum_fragment_size(size_t max_fragment) - { - if(max_fragment == 0) - m_max_fragment = MAX_PLAINTEXT_SIZE; - else - m_max_fragment = clamp(max_fragment, 128, MAX_PLAINTEXT_SIZE); - } - -/* -* Reset the state -*/ -void Record_Writer::reset() - { - set_maximum_fragment_size(0); - - m_write_cipherstate.reset(); - - m_version = Protocol_Version(); - - m_write_seq_no = 0; - } - -/* -* Set the version to use -*/ -void Record_Writer::set_version(Protocol_Version version) - { - m_version = version; - } - -/* -* Set the keys for writing -*/ -void Record_Writer::change_cipher_spec(Connection_Side side, - const Ciphersuite& suite, - const Session_Keys& keys, - byte compression_method) - { - if(compression_method != NO_COMPRESSION) - throw Internal_Error("Negotiated unknown compression algorithm"); - - /* - RFC 4346: - A sequence number is incremented after each record: specifically, - the first record transmitted under a particular connection state - MUST use sequence number 0 - */ - m_write_seq_no = 0; - - m_write_cipherstate.reset( - new Connection_Cipher_State(m_version, side, suite, keys) - ); - } - -/* -* Send one or more records to the other side -*/ -void Record_Writer::send_array(byte type, const byte input[], size_t length) - { - if(length == 0) - return; - - /* - * If using CBC mode in SSLv3/TLS v1.0, send a single byte of - * plaintext to randomize the (implicit) IV of the following main - * block. If using a stream cipher, or TLS v1.1 or higher, this - * isn't necessary. - * - * An empty record also works but apparently some implementations do - * not like this (https://bugzilla.mozilla.org/show_bug.cgi?id=665814) - * - * See http://www.openssl.org/~bodo/tls-cbc.txt for background. - */ - if((type == APPLICATION_DATA) && - (m_write_cipherstate->block_size() > 0) && - (m_write_cipherstate->iv_size() == 0)) - { - send_record(type, &input[0], 1); - input += 1; - length -= 1; - } - - while(length) - { - const size_t sending = std::min(length, m_max_fragment); - send_record(type, &input[0], sending); - - input += sending; - length -= sending; - } - } - -/* -* Encrypt and send the record -*/ -void Record_Writer::send_record(byte type, const byte input[], size_t length) - { - if(length >= MAX_PLAINTEXT_SIZE) - throw Internal_Error("Record_Writer: Compressed packet is too big"); - - const size_t written = write_record(m_writebuf, - type, - input, - length, - m_write_seq_no, - m_version, - m_write_cipherstate.get(), - m_rng); - - m_write_seq_no += 1; - m_output_fn(&m_writebuf[0], written); - } - -} - -} diff --git a/src/tls/tls_channel.cpp b/src/tls/tls_channel.cpp index 87b58f242..11a4971c2 100644 --- a/src/tls/tls_channel.cpp +++ b/src/tls/tls_channel.cpp @@ -10,13 +10,14 @@ #include <botan/internal/tls_messages.h> #include <botan/internal/tls_heartbeats.h> #include <botan/internal/assert.h> +#include <botan/internal/rounding.h> #include <botan/loadstor.h> namespace Botan { namespace TLS { -Channel::Channel(std::function<void (const byte[], size_t)> socket_output_fn, +Channel::Channel(std::function<void (const byte[], size_t)> output_fn, std::function<void (const byte[], size_t, Alert)> proc_fn, std::function<bool (const Session&)> handshake_complete, Session_Manager& session_manager, @@ -25,8 +26,9 @@ Channel::Channel(std::function<void (const byte[], size_t)> socket_output_fn, m_state(nullptr), m_rng(rng), m_session_manager(session_manager), - m_writer(socket_output_fn, rng), - m_proc_fn(proc_fn) + m_proc_fn(proc_fn), + m_output_fn(output_fn), + m_writebuf(TLS_HEADER_SIZE + MAX_CIPHERTEXT_SIZE) { } @@ -37,7 +39,6 @@ Channel::~Channel() void Channel::set_protocol_version(Protocol_Version version) { m_state->set_version(version); - m_writer.set_version(version); m_reader.set_version(version); } @@ -46,10 +47,14 @@ Protocol_Version Channel::current_protocol_version() const return m_reader.get_version(); } -void Channel::set_maximum_fragment_size(size_t maximum) +void Channel::set_maximum_fragment_size(size_t max_fragment) { - m_reader.set_maximum_fragment_size(maximum); - m_writer.set_maximum_fragment_size(maximum); + m_reader.set_maximum_fragment_size(max_fragment); + + if(max_fragment == 0) + m_max_fragment = MAX_PLAINTEXT_SIZE; + else + m_max_fragment = clamp(max_fragment, 128, MAX_PLAINTEXT_SIZE); } void Channel::change_cipher_spec_reader(Connection_Side side) @@ -62,10 +67,23 @@ void Channel::change_cipher_spec_reader(Connection_Side side) void Channel::change_cipher_spec_writer(Connection_Side side) { - m_writer.change_cipher_spec(side, - m_state->ciphersuite(), - m_state->session_keys(), - m_state->server_hello()->compression_method()); + if(m_state->server_hello()->compression_method()!= NO_COMPRESSION) + throw Internal_Error("Negotiated unknown compression algorithm"); + + /* + RFC 4346: + A sequence number is incremented after each record: specifically, + the first record transmitted under a particular connection state + MUST use sequence number 0 + */ + m_write_seq_no = 0; + + m_write_cipherstate.reset( + new Connection_Cipher_State(current_protocol_version(), + side, + m_state->ciphersuite(), + m_state->session_keys()) + ); } void Channel::activate_session(const std::vector<byte>& session_id) @@ -206,7 +224,7 @@ size_t Channel::received_data(const byte buf[], size_t buf_size) m_state.reset(); - m_writer.reset(); + m_write_cipherstate.reset(); m_reader.reset(); } } @@ -253,9 +271,66 @@ void Channel::heartbeat(const byte payload[], size_t payload_size) } } +void Channel::send_record(byte type, const byte input[], size_t length) + { + if(length == 0) + return; + + /* + * If using CBC mode in SSLv3/TLS v1.0, send a single byte of + * plaintext to randomize the (implicit) IV of the following main + * block. If using a stream cipher, or TLS v1.1 or higher, this + * isn't necessary. + * + * An empty record also works but apparently some implementations do + * not like this (https://bugzilla.mozilla.org/show_bug.cgi?id=665814) + * + * See http://www.openssl.org/~bodo/tls-cbc.txt for background. + */ + if((type == APPLICATION_DATA) && + (m_write_cipherstate->block_size() > 0) && + (m_write_cipherstate->iv_size() == 0)) + { + write_record(type, &input[0], 1); + input += 1; + length -= 1; + } + + while(length) + { + const size_t sending = std::min(length, m_max_fragment); + write_record(type, &input[0], sending); + + input += sending; + length -= sending; + } + } + void Channel::send_record(byte record_type, const std::vector<byte>& record) { - m_writer.send(record_type, record); + send_record(record_type, &record[0], record.size()); + } + +void Channel::write_record(byte record_type, const byte input[], size_t length) + { + if(length >= m_max_fragment) + throw Internal_Error("Record is larger than allowed fragment size"); + + Protocol_Version version = current_protocol_version(); + if(!version.valid()) + version = m_state->handshake_io().initial_record_version(); + + const size_t written = TLS::write_record(m_writebuf, + record_type, + input, + length, + m_write_seq_no, + version, + m_write_cipherstate.get(), + m_rng); + + m_write_seq_no += 1; + m_output_fn(&m_writebuf[0], written); } void Channel::send(const byte buf[], size_t buf_size) @@ -263,7 +338,7 @@ void Channel::send(const byte buf[], size_t buf_size) if(!is_active()) throw std::runtime_error("Data cannot be sent on inactive TLS connection"); - m_writer.send_array(APPLICATION_DATA, buf, buf_size); + send_record(APPLICATION_DATA, buf, buf_size); } void Channel::send(const std::string& string) @@ -293,7 +368,7 @@ void Channel::send_alert(const Alert& alert) m_connection_closed = true; m_state.reset(); - m_writer.reset(); + m_write_cipherstate.reset(); } } diff --git a/src/tls/tls_channel.h b/src/tls/tls_channel.h index e0b19758a..3b53d3539 100644 --- a/src/tls/tls_channel.h +++ b/src/tls/tls_channel.h @@ -164,7 +164,6 @@ class BOTAN_DLL Channel RandomNumberGenerator& m_rng; Session_Manager& m_session_manager; - Record_Writer m_writer; private: Record_Reader m_reader; protected: @@ -173,7 +172,18 @@ class BOTAN_DLL Channel Secure_Renegotiation_State m_secure_renegotiation; private: + void send_record(byte type, const byte input[], size_t length); + + void write_record(byte type, const byte input[], size_t length); + std::function<void (const byte[], size_t, Alert)> m_proc_fn; + std::function<void (const byte[], size_t)> m_output_fn; + + std::vector<byte> m_writebuf; + std::unique_ptr<Connection_Cipher_State> m_write_cipherstate; + u64bit m_write_seq_no = 0; + + size_t m_max_fragment = MAX_PLAINTEXT_SIZE; bool m_peer_supports_heartbeats = false; bool m_heartbeat_sending_allowed = false; diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp index 0976555d9..d2508d579 100644 --- a/src/tls/tls_client.cpp +++ b/src/tls/tls_client.cpp @@ -94,9 +94,6 @@ void Client::initiate_handshake(bool force_full_renegotiation, { m_state.reset(new_handshake_state()); - if(!m_writer.record_version_set()) - m_writer.set_version(m_state->handshake_io().initial_record_version()); - if(m_state->version().is_datagram_protocol()) m_state->set_expected_next(HELLO_VERIFY_REQUEST); m_state->set_expected_next(SERVER_HELLO); diff --git a/src/tls/tls_record.h b/src/tls/tls_record.h index 1f21e9a00..a1abec9e5 100644 --- a/src/tls/tls_record.h +++ b/src/tls/tls_record.h @@ -96,52 +96,6 @@ size_t read_record(std::vector<byte>& read_buffer, Connection_Cipher_State* cipherstate); /** -* TLS Record Writer -*/ -class BOTAN_DLL Record_Writer - { - public: - void send_array(byte type, const byte input[], size_t length); - - void send(byte type, const std::vector<byte>& input) - { send_array(type, &input[0], input.size()); } - - void change_cipher_spec(Connection_Side side, - const Ciphersuite& suite, - const Session_Keys& keys, - byte compression_method); - - void set_version(Protocol_Version version); - - bool record_version_set() const { return m_version.valid(); } - - void reset(); - - void set_maximum_fragment_size(size_t max_fragment); - - Record_Writer(std::function<void (const byte[], size_t)> output_fn, - RandomNumberGenerator& rng); - - Record_Writer(const Record_Writer&) = delete; - Record_Writer& operator=(const Record_Writer&) = delete; - private: - void send_record(byte type, const byte input[], size_t length); - - std::function<void (const byte[], size_t)> m_output_fn; - - std::vector<byte> m_writebuf; - - std::unique_ptr<Connection_Cipher_State> m_write_cipherstate; - - RandomNumberGenerator& m_rng; - - size_t m_max_fragment = MAX_PLAINTEXT_SIZE; - - u64bit m_write_seq_no = 0; - Protocol_Version m_version; - }; - -/** * TLS Record Reader */ class BOTAN_DLL Record_Reader |