aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-09-21 17:25:03 -0400
committerJack Lloyd <[email protected]>2016-09-21 17:25:03 -0400
commit72eaa39bf553ba3575fdd0681a14e0cc1e145563 (patch)
treeecaf56dea6b1183415812f8020c60e455a2cf169
parentafe735aee31bfc7916305e285d7aa73df070de52 (diff)
Cleanup TLS CBC encryption record code
The EtM and MtE codepaths had a lot of duplicated code. Tests ok, also did manual testing against a few online machines including the EtM test server at eid.vx4.net
-rw-r--r--src/lib/tls/tls_record.cpp199
1 files changed, 69 insertions, 130 deletions
diff --git a/src/lib/tls/tls_record.cpp b/src/lib/tls/tls_record.cpp
index 877b81b41..fc6907db2 100644
--- a/src/lib/tls/tls_record.cpp
+++ b/src/lib/tls/tls_record.cpp
@@ -155,6 +155,33 @@ Connection_Cipher_State::format_ad(u64bit msg_sequence,
return ad;
}
+namespace {
+
+void cbc_encrypt_record(const BlockCipher& bc,
+ secure_vector<byte>& cbc_state,
+ byte buf[],
+ size_t buf_size)
+ {
+ const size_t block_size = bc.block_size();
+ const size_t blocks = buf_size / block_size;
+ BOTAN_ASSERT(buf_size % block_size == 0, "CBC input");
+ BOTAN_ASSERT(blocks > 0, "Expected at least 1 block");
+
+ xor_buf(buf, cbc_state.data(), block_size);
+ bc.encrypt(buf);
+
+ for(size_t i = 1; i < blocks; ++i)
+ {
+ xor_buf(&buf[block_size*i], &buf[block_size*(i-1)], block_size);
+ bc.encrypt(&buf[block_size*i]);
+ }
+
+ cbc_state.assign(&buf[block_size*(blocks-1)],
+ &buf[block_size*blocks]);
+ }
+
+}
+
void write_record(secure_vector<byte>& output,
Record_Message msg,
Protocol_Version version,
@@ -220,147 +247,59 @@ void write_record(secure_vector<byte>& output,
const size_t iv_size = cs->iv_size();
const size_t mac_size = cs->mac_size();
- if(!cs->uses_encrypt_then_mac())
- {
- cs->mac()->update(cs->format_ad(seq, msg.get_type(), version, static_cast<u16bit>(msg.get_size())));
- cs->mac()->update(msg.get_data(), msg.get_size());
+ const size_t input_size =
+ iv_size + msg.get_size() + 1 + (cs->uses_encrypt_then_mac() ? 0 : mac_size);
+ const size_t enc_size = round_up(input_size, block_size);
+ const size_t pad_val = enc_size - input_size;
+ const size_t buf_size = enc_size + (cs->uses_encrypt_then_mac() ? mac_size : 0);
- const size_t buf_size = round_up(
- iv_size + msg.get_size() + mac_size + (block_size ? 1 : 0),
- block_size);
+ BOTAN_ASSERT(enc_size % block_size == 0,
+ "Buffer is an even multiple of block size");
- if(buf_size > MAX_CIPHERTEXT_SIZE)
- throw Internal_Error("Output record is larger than allowed by protocol");
+ if(buf_size > MAX_CIPHERTEXT_SIZE)
+ throw Internal_Error("Output record is larger than allowed by protocol");
- output.push_back(get_byte(0, static_cast<u16bit>(buf_size)));
- output.push_back(get_byte(1, static_cast<u16bit>(buf_size)));
+ output.push_back(get_byte(0, static_cast<u16bit>(buf_size)));
+ output.push_back(get_byte(1, static_cast<u16bit>(buf_size)));
- const size_t header_size = output.size();
+ const size_t header_size = output.size();
- if(iv_size)
- {
- output.resize(output.size() + iv_size);
- rng.randomize(&output[output.size() - iv_size], iv_size);
- }
+ if(iv_size)
+ {
+ output.resize(output.size() + iv_size);
+ rng.randomize(&output[output.size() - iv_size], iv_size);
+ }
- output.insert(output.end(), msg.get_data(), msg.get_data() + msg.get_size());
+ output.insert(output.end(), msg.get_data(), msg.get_data() + msg.get_size());
+ if(!cs->uses_encrypt_then_mac())
+ {
output.resize(output.size() + mac_size);
- cs->mac()->final(&output[output.size() - mac_size]);
-
- if(block_size)
- {
- const size_t pad_val =
- buf_size - (iv_size + msg.get_size() + mac_size + 1);
-
- for(size_t i = 0; i != pad_val + 1; ++i)
- output.push_back(static_cast<byte>(pad_val));
- }
-
- if(buf_size > MAX_CIPHERTEXT_SIZE)
- throw Internal_Error("Produced ciphertext larger than protocol allows");
- BOTAN_ASSERT_EQUAL(buf_size + header_size, output.size(),
- "Output buffer is sized properly");
-
- if(BlockCipher* bc = cs->block_cipher())
- {
- secure_vector<byte>& cbc_state = cs->cbc_state();
-
- BOTAN_ASSERT(buf_size % block_size == 0,
- "Buffer is an even multiple of block size");
-
- byte* buf = &output[header_size];
-
- const size_t blocks = buf_size / block_size;
-
- xor_buf(buf, cbc_state.data(), block_size);
- bc->encrypt(buf);
+ cs->mac()->update(cs->format_ad(seq, msg.get_type(), version, static_cast<u16bit>(msg.get_size())));
+ cs->mac()->update(msg.get_data(), msg.get_size());
+ cs->mac()->final(&output[output.size() - mac_size]);
- for(size_t i = 1; i < blocks; ++i)
- {
- xor_buf(&buf[block_size*i], &buf[block_size*(i-1)], block_size);
- bc->encrypt(&buf[block_size*i]);
- }
+ for(size_t i = 0; i != pad_val + 1; ++i)
+ output.push_back(static_cast<byte>(pad_val));
- cbc_state.assign(&buf[block_size*(blocks-1)],
- &buf[block_size*blocks]);
- }
- else
- {
- throw Internal_Error("NULL cipher not supported");
- }
+ cbc_encrypt_record(*cs->block_cipher(), cs->cbc_state(), &output[header_size], buf_size);
}
else
{
- const size_t enc_size = round_up(
- iv_size + msg.get_size() + (block_size ? 1 : 0),
- block_size);
-
- const size_t buf_size = enc_size + mac_size;
-
- if(buf_size > MAX_CIPHERTEXT_SIZE)
- throw Internal_Error("Output record is larger than allowed by protocol");
-
- output.push_back(get_byte<u16bit>(0, buf_size));
- output.push_back(get_byte<u16bit>(1, buf_size));
-
- const size_t header_size = output.size();
-
- if(iv_size)
- {
- output.resize(output.size() + iv_size);
- rng.randomize(&output[output.size() - iv_size], iv_size);
- }
-
- output.insert(output.end(), msg.get_data(), msg.get_data() + msg.get_size());
-
- if(block_size)
- {
- const size_t pad_val =
- enc_size - (iv_size + msg.get_size() + 1);
-
- for(size_t i = 0; i != pad_val + 1; ++i)
- output.push_back(pad_val);
- }
-
- if(BlockCipher* bc = cs->block_cipher())
- {
- secure_vector<byte>& cbc_state = cs->cbc_state();
+ for(size_t i = 0; i != pad_val + 1; ++i)
+ output.push_back(pad_val);
- BOTAN_ASSERT( enc_size % block_size == 0,
- "Buffer is an even multiple of block size");
+ cbc_encrypt_record(*cs->block_cipher(), cs->cbc_state(), &output[header_size], enc_size);
+ cs->mac()->update(cs->format_ad(seq, msg.get_type(), version, enc_size));
+ cs->mac()->update(&output[header_size], enc_size);
- byte* buf = &output[header_size];
-
- const size_t blocks = enc_size / block_size;
-
- xor_buf(buf, cbc_state.data(), block_size);
- bc->encrypt(buf);
-
- for(size_t i = 1; i < blocks; ++i)
- {
- xor_buf(&buf[block_size*i], &buf[block_size*(i-1)], block_size);
- bc->encrypt(&buf[block_size*i]);
- }
-
- cbc_state.assign(&buf[block_size*(blocks-1)],
- &buf[block_size*blocks]);
-
- cs->mac()->update(cs->format_ad(seq, msg.get_type(), version, enc_size));
- cs->mac()->update(buf, enc_size);
-
- output.resize(output.size() + mac_size);
- cs->mac()->final(&output[output.size() - mac_size]);
+ output.resize(output.size() + mac_size);
+ cs->mac()->final(&output[output.size() - mac_size]);
+ }
- BOTAN_ASSERT_EQUAL(buf_size + header_size, output.size(),
+ BOTAN_ASSERT_EQUAL(buf_size + header_size, output.size(),
"Output buffer is sized properly");
- }
- else
- {
- throw Internal_Error("NULL cipher not supported");
- }
- }
}
namespace {
@@ -500,7 +439,7 @@ void decrypt_record(secure_vector<byte>& output,
u16bit pad_size = tls_padding_check(record_contents, record_len);
// This mask is zero if there is not enough room in the packet to get
- // a valid MAC. We have to accept empty packets, since otherwise we
+ // a valid MAC. We have to accept empty packets, since otherwise we
// are not compatible with the BEAST countermeasure (thus record_len+1).
const u16bit size_ok_mask = CT::is_lte<u16bit>(static_cast<u16bit>(mac_size + pad_size + iv_size), static_cast<u16bit>(record_len + 1));
pad_size &= size_ok_mask;
@@ -545,7 +484,7 @@ void decrypt_record(secure_vector<byte>& output,
// This early exit does not leak info because all the values are public
if((record_len < mac_size + iv_size) || ( enc_size % cs.block_size() != 0))
throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure");
-
+
cs.mac()->update(cs.format_ad(record_sequence, record_type, record_version, enc_size));
cs.mac()->update(record_contents, enc_size);
@@ -553,14 +492,14 @@ void decrypt_record(secure_vector<byte>& output,
cs.mac()->final(mac_buf.data());
const size_t mac_offset = enc_size;
-
+
const bool mac_ok = same_mem(&record_contents[mac_offset], mac_buf.data(), mac_size);
-
+
if(!mac_ok)
{
- throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure");
+ throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure");
}
-
+
cbc_decrypt_record(record_contents, enc_size, cs, *bc);
// 0 if padding was invalid, otherwise 1 + padding_bytes
@@ -568,7 +507,7 @@ void decrypt_record(secure_vector<byte>& output,
const byte* plaintext_block = &record_contents[iv_size];
const u16bit plaintext_length = enc_size - iv_size - pad_size;
-
+
output.assign(plaintext_block, plaintext_block + plaintext_length);
}
}