aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/tls/info.txt1
-rw-r--r--src/tls/rec_wri.cpp144
-rw-r--r--src/tls/tls_channel.cpp105
-rw-r--r--src/tls/tls_channel.h12
-rw-r--r--src/tls/tls_client.cpp3
-rw-r--r--src/tls/tls_record.h46
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