aboutsummaryrefslogtreecommitdiffstats
path: root/src/ssl/rec_read.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssl/rec_read.cpp')
-rw-r--r--src/ssl/rec_read.cpp120
1 files changed, 69 insertions, 51 deletions
diff --git a/src/ssl/rec_read.cpp b/src/ssl/rec_read.cpp
index 95059dbf2..8f8e5dc1e 100644
--- a/src/ssl/rec_read.cpp
+++ b/src/ssl/rec_read.cpp
@@ -1,6 +1,6 @@
/**
-* TLS Record Reading
-* (C) 2004-2006 Jack Lloyd
+* TLS Record Reading
+* (C) 2004-2010 Jack Lloyd
*
* Released under the terms of the Botan license
*/
@@ -13,23 +13,15 @@
namespace Botan {
/**
-* Record_Reader Constructor
-*/
-Record_Reader::Record_Reader(Socket& sock) : socket(sock)
- {
- reset();
- }
-
-/**
* Reset the state
*/
void Record_Reader::reset()
{
- compress.reset();
cipher.reset();
mac.reset();
- do_compress = false;
- mac_size = pad_amount = 0;
+ mac_size = 0;
+ block_size = 0;
+ iv_size = 0;
major = minor = 0;
seq_no = 0;
}
@@ -39,7 +31,7 @@ void Record_Reader::reset()
*/
void Record_Reader::set_version(Version_Code version)
{
- if(version != SSL_V3 && version != TLS_V10)
+ if(version != SSL_V3 && version != TLS_V10 && version != TLS_V11)
throw Invalid_Argument("Record_Reader: Invalid protocol version");
major = (version >> 8) & 0xFF;
@@ -47,15 +39,6 @@ void Record_Reader::set_version(Version_Code version)
}
/**
-* Set the compression algorithm
-*/
-void Record_Reader::set_compressor(Filter* compressor)
- {
- compress.append(compressor);
- do_compress = true;
- }
-
-/**
* Set the keys for reading
*/
void Record_Reader::set_keys(const CipherSuite& suite, const SessionKeys& keys,
@@ -89,12 +72,18 @@ void Record_Reader::set_keys(const CipherSuite& suite, const SessionKeys& keys,
cipher_algo + "/CBC/NoPadding",
cipher_key, iv, DECRYPTION)
);
- pad_amount = block_size_of(cipher_algo);
+ block_size = block_size_of(cipher_algo);
+
+ if(major == 3 && minor >= 2)
+ iv_size = block_size;
+ else
+ iv_size = 0;
}
else if(have_stream_cipher(cipher_algo))
{
cipher.append(get_cipher(cipher_algo, cipher_key, DECRYPTION));
- pad_amount = 0;
+ block_size = 0;
+ iv_size = 0;
}
else
throw Invalid_Argument("Record_Reader: Unknown cipher " + cipher_algo);
@@ -112,75 +101,102 @@ void Record_Reader::set_keys(const CipherSuite& suite, const SessionKeys& keys,
throw Invalid_Argument("Record_Reader: Unknown hash " + mac_algo);
}
+void Record_Reader::add_input(const byte input[], u32bit input_size)
+ {
+ input_queue.write(input, input_size);
+ }
+
/**
* Retrieve the next record
*/
-SecureVector<byte> Record_Reader::get_record(byte& msg_type)
+u32bit Record_Reader::get_record(byte& msg_type,
+ MemoryRegion<byte>& output)
{
byte header[5] = { 0 };
- u32bit got = socket.read(header, sizeof(header));
+ const u32bit have_in_queue = input_queue.size();
- if(got == 0)
- {
- msg_type = CONNECTION_CLOSED;
- return SecureVector<byte>();
- }
- else if(got != sizeof(header))
- throw Decoding_Error("Record_Reader: Record truncated");
+ if(have_in_queue < sizeof(header))
+ return (sizeof(header) - have_in_queue);
- msg_type = header[0];
+ /*
+ * We peek first to make sure we have the full record
+ */
+ input_queue.peek(header, sizeof(header));
- const u16bit version = make_u16bit(header[1], header[2]);
+ const u16bit version = make_u16bit(header[1], header[2]);
+ const u16bit record_len = make_u16bit(header[3], header[4]);
if(major && (header[1] != major || header[2] != minor))
throw TLS_Exception(PROTOCOL_VERSION,
"Record_Reader: Got unexpected version");
- SecureVector<byte> buffer(make_u16bit(header[3], header[4]));
- if(socket.read(buffer, buffer.size()) != buffer.size())
- throw Decoding_Error("Record_Reader: Record truncated");
+ // If insufficient data, return without doing anything
+ if(have_in_queue < (sizeof(header) + record_len))
+ return (sizeof(header) + record_len - have_in_queue);
+
+ SecureVector<byte> buffer(record_len);
+ input_queue.read(header, sizeof(header)); // pull off the header
+ input_queue.read(buffer, buffer.size());
+
+ /*
+ * We are handshaking, no crypto to do so return as-is
+ * TODO: Check msg_type to confirm a handshake?
+ */
if(mac_size == 0)
- return buffer;
+ {
+ msg_type = header[0];
+ output = buffer;
+ return 0; // got a full record
+ }
+
+ // Otherwise, decrypt, check MAC, return plaintext
cipher.process_msg(buffer);
SecureVector<byte> plaintext = cipher.read_all(Pipe::LAST_MESSAGE);
u32bit pad_size = 0;
- if(pad_amount)
+
+ if(block_size)
{
byte pad_value = plaintext[plaintext.size()-1];
pad_size = pad_value + 1;
+ /*
+ * Check the padding; if it is wrong, then say we have 0 bytes of
+ * padding, which should ensure that the MAC check below does not
+ * suceed. This hides a timing channel.
+ *
+ * This particular countermeasure is recommended in the TLS 1.2
+ * spec (RFC 5246) in section 6.2.3.2
+ */
if(version == SSL_V3)
{
- if(pad_value > pad_amount)
- throw TLS_Exception(BAD_RECORD_MAC,
- "Record_Reader: Bad padding");
+ if(pad_value > block_size)
+ pad_size = 0;
}
else
{
for(u32bit j = 0; j != pad_size; j++)
if(plaintext[plaintext.size()-j-1] != pad_value)
- throw TLS_Exception(BAD_RECORD_MAC,
- "Record_Reader: Bad padding");
+ pad_size = 0;
}
}
- if(plaintext.size() < mac_size + pad_size)
+ if(plaintext.size() < mac_size + pad_size + iv_size)
throw Decoding_Error("Record_Reader: Record truncated");
const u32bit mac_offset = plaintext.size() - (mac_size + pad_size);
SecureVector<byte> recieved_mac(plaintext.begin() + mac_offset,
mac_size);
- const u16bit plain_length = plaintext.size() - (mac_size + pad_size);
+ const u16bit plain_length = plaintext.size() - (mac_size + pad_size + iv_size);
mac.start_msg();
for(u32bit j = 0; j != 8; j++)
mac.write(get_byte(j, seq_no));
- mac.write(msg_type);
+ mac.write(header[0]); // msg_type
if(version != SSL_V3)
for(u32bit j = 0; j != 2; j++)
@@ -188,7 +204,7 @@ SecureVector<byte> Record_Reader::get_record(byte& msg_type)
for(u32bit j = 0; j != 2; j++)
mac.write(get_byte(j, plain_length));
- mac.write(plaintext, plain_length);
+ mac.write(&plaintext[iv_size], plain_length);
mac.end_msg();
++seq_no;
@@ -198,7 +214,9 @@ SecureVector<byte> Record_Reader::get_record(byte& msg_type)
if(recieved_mac != computed_mac)
throw TLS_Exception(BAD_RECORD_MAC, "Record_Reader: MAC failure");
- return SecureVector<byte>(plaintext, mac_offset);
+ msg_type = header[0];
+ output.set(&plaintext[iv_size], plain_length);
+ return 0;
}
}