Botan 3.4.0
Crypto and TLS for C&
tls_cbc.cpp
Go to the documentation of this file.
1/*
2* TLS CBC Record Handling
3* (C) 2012,2013,2014,2015,2016,2020 Jack Lloyd
4* (C) 2016 Juraj Somorovsky
5* (C) 2016 Matthias Gierlings
6* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
7*
8* Botan is released under the Simplified BSD License (see license.txt)
9*/
10
11#include <botan/internal/tls_cbc.h>
12
13#include <botan/internal/cbc.h>
14
15#include <botan/tls_alert.h>
16#include <botan/tls_exceptn.h>
17#include <botan/internal/ct_utils.h>
18#include <botan/internal/loadstor.h>
19#include <botan/internal/rounding.h>
20
21namespace Botan::TLS {
22
23/*
24* TLS_CBC_HMAC_AEAD_Mode Constructor
25*/
27 std::unique_ptr<BlockCipher> cipher,
28 std::unique_ptr<MessageAuthenticationCode> mac,
29 size_t cipher_keylen,
30 size_t mac_keylen,
31 Protocol_Version version,
32 bool use_encrypt_then_mac) :
33 m_cipher_name(cipher->name()),
34 m_mac_name(mac->name()),
35 m_cipher_keylen(cipher_keylen),
36 m_mac_keylen(mac_keylen),
37 m_use_encrypt_then_mac(use_encrypt_then_mac) {
38 m_tag_size = mac->output_length();
39 m_block_size = cipher->block_size();
40
41 m_iv_size = m_block_size;
42
43 m_is_datagram = version.is_datagram_protocol();
44
45 m_mac = std::move(mac);
46
47 auto null_padding = std::make_unique<Null_Padding>();
49 m_cbc = std::make_unique<CBC_Encryption>(std::move(cipher), std::move(null_padding));
50 } else {
51 m_cbc = std::make_unique<CBC_Decryption>(std::move(cipher), std::move(null_padding));
52 }
53}
54
56 cbc().clear();
57 mac().clear();
58 reset();
59}
60
62 cbc_state().clear();
63 m_ad.clear();
64 m_msg.clear();
65}
66
67std::string TLS_CBC_HMAC_AEAD_Mode::name() const {
68 return "TLS_CBC(" + m_cipher_name + "," + m_mac_name + ")";
69}
70
72 return 1; // just buffers anyway
73}
74
76 return 1; // just buffers anyway
77}
78
80 if(m_cbc_state.empty()) {
81 return nl == block_size();
82 }
83 return nl == iv_size();
84}
85
87 return Key_Length_Specification(m_cipher_keylen + m_mac_keylen);
88}
89
93
94void TLS_CBC_HMAC_AEAD_Mode::key_schedule(std::span<const uint8_t> key) {
95 // Both keys are of fixed length specified by the ciphersuite
96
97 if(key.size() != m_cipher_keylen + m_mac_keylen) {
98 throw Invalid_Key_Length(name(), key.size());
99 }
100
101 mac().set_key(key.first(m_mac_keylen));
102 cbc().set_key(key.subspan(m_mac_keylen, m_cipher_keylen));
103}
104
105void TLS_CBC_HMAC_AEAD_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
107 throw Invalid_IV_Length(name(), nonce_len);
108 }
109
110 m_msg.clear();
111
112 if(nonce_len > 0) {
113 m_cbc_state.assign(nonce, nonce + nonce_len);
114 }
115}
116
117size_t TLS_CBC_HMAC_AEAD_Mode::process_msg(uint8_t buf[], size_t sz) {
118 m_msg.insert(m_msg.end(), buf, buf + sz);
119 return 0;
120}
121
122std::vector<uint8_t> TLS_CBC_HMAC_AEAD_Mode::assoc_data_with_len(uint16_t len) {
123 std::vector<uint8_t> ad = m_ad;
124 BOTAN_ASSERT(ad.size() == 13, "Expected AAD size");
125 ad[11] = get_byte<0>(len);
126 ad[12] = get_byte<1>(len);
127 return ad;
128}
129
130void TLS_CBC_HMAC_AEAD_Mode::set_associated_data_n(size_t idx, std::span<const uint8_t> ad) {
131 BOTAN_ARG_CHECK(idx == 0, "TLS 1.2 CBC/HMAC: cannot handle non-zero index in set_associated_data_n");
132 if(ad.size() != 13) {
133 throw Invalid_Argument("Invalid TLS AEAD associated data length");
134 }
135 m_ad.assign(ad.begin(), ad.end());
136}
137
138void TLS_CBC_HMAC_AEAD_Encryption::set_associated_data_n(size_t idx, std::span<const uint8_t> ad) {
140
142 // AAD hack for EtM
143 // EtM uses ciphertext size instead of plaintext size for AEAD input
144 const uint16_t pt_size = make_uint16(assoc_data()[11], assoc_data()[12]);
145 const uint16_t enc_size = static_cast<uint16_t>(round_up(iv_size() + pt_size + 1, block_size()));
148 }
149}
150
151void TLS_CBC_HMAC_AEAD_Encryption::cbc_encrypt_record(secure_vector<uint8_t>& buffer,
152 size_t offset,
153 size_t padding_length) {
154 // We always do short padding:
156
157 buffer.resize(buffer.size() + padding_length);
158
159 const uint8_t padding_val = static_cast<uint8_t>(padding_length - 1);
160
163 CT::poison(buffer.data(), buffer.size());
164
165 const size_t last_block_starts = buffer.size() - block_size();
166 const size_t padding_starts = buffer.size() - padding_length;
167 for(size_t i = last_block_starts; i != buffer.size(); ++i) {
169 buffer[i] = add_padding.select(padding_val, buffer[i]);
170 }
171
174 CT::unpoison(buffer.data(), buffer.size());
175
176 cbc().start(cbc_state());
177 cbc().process(&buffer[offset], buffer.size() - offset);
178
179 cbc_state().assign(buffer.data() + (buffer.size() - block_size()), buffer.data() + buffer.size());
180}
181
182size_t TLS_CBC_HMAC_AEAD_Encryption::output_length(size_t input_length) const {
183 return round_up(input_length + 1 + (use_encrypt_then_mac() ? 0 : tag_size()), block_size()) +
184 (use_encrypt_then_mac() ? tag_size() : 0);
185}
186
187void TLS_CBC_HMAC_AEAD_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
188 update(buffer, offset);
189
190 const size_t msg_size = msg().size();
191
192 const size_t input_size = msg_size + 1 + (use_encrypt_then_mac() ? 0 : tag_size());
193 const size_t enc_size = round_up(input_size, block_size());
195
196 const uint8_t padding_val = static_cast<uint8_t>(enc_size - input_size);
197 const size_t padding_length = static_cast<size_t>(padding_val) + 1;
198
199 buffer.reserve(offset + msg_size + padding_length + tag_size());
200 buffer.resize(offset + msg_size);
201 copy_mem(&buffer[offset], msg().data(), msg_size);
202
203 mac().update(assoc_data());
204
206 if(iv_size() > 0) {
207 mac().update(cbc_state());
208 }
209
210 cbc_encrypt_record(buffer, offset, padding_length);
211 mac().update(&buffer[offset], enc_size);
212 buffer.resize(buffer.size() + tag_size());
213 mac().final(&buffer[buffer.size() - tag_size()]);
214 } else {
215 mac().update(&buffer[offset], msg_size);
216 buffer.resize(buffer.size() + tag_size());
217 mac().final(&buffer[buffer.size() - tag_size()]);
218 cbc_encrypt_record(buffer, offset, padding_length);
219 }
220}
221
222/*
223* Checks the TLS padding. Returns 0 if the padding is invalid (we
224* count the padding_length field as part of the padding size so a
225* valid padding will always be at least one byte long), or the length
226* of the padding otherwise. This is actually padding_length + 1
227* because both the padding and padding_length fields are padding from
228* our perspective.
229*
230* Returning 0 in the error case should ensure the MAC check will fail.
231* This approach is suggested in section 6.2.3.2 of RFC 5246.
232*/
233uint16_t check_tls_cbc_padding(const uint8_t record[], size_t record_len) {
234 if(record_len == 0 || record_len > 0xFFFF) {
235 return 0;
236 }
237
238 const uint16_t rec16 = static_cast<uint16_t>(record_len);
239
240 /*
241 * TLS v1.0 and up require all the padding bytes be the same value
242 * and allows up to 255 bytes.
243 */
244
245 const uint16_t to_check = std::min<uint16_t>(256, static_cast<uint16_t>(record_len));
246 const uint8_t pad_byte = record[record_len - 1];
247 const uint16_t pad_bytes = 1 + pad_byte;
248
249 auto pad_invalid = CT::Mask<uint16_t>::is_lt(rec16, pad_bytes);
250
251 for(uint16_t i = rec16 - to_check; i != rec16; ++i) {
252 const uint16_t offset = rec16 - i;
253 const auto in_pad_range = CT::Mask<uint16_t>::is_lte(offset, pad_bytes);
254 const auto pad_correct = CT::Mask<uint16_t>::is_equal(record[i], pad_byte);
255 pad_invalid |= in_pad_range & ~pad_correct;
256 }
257
258 return pad_invalid.if_not_set_return(pad_bytes);
259}
260
261void TLS_CBC_HMAC_AEAD_Decryption::cbc_decrypt_record(uint8_t record_contents[], size_t record_len) {
262 if(record_len == 0 || record_len % block_size() != 0) {
263 throw Decoding_Error("Received TLS CBC ciphertext with invalid length");
264 }
265
266 cbc().start(cbc_state());
268
270}
271
272size_t TLS_CBC_HMAC_AEAD_Decryption::output_length(size_t /*input_length*/) const {
273 /*
274 * We don't know this because the padding is arbitrary
275 */
276 return 0;
277}
278
279/*
280* This function performs additional compression calls in order
281* to protect from the Lucky 13 attack. It adds new compression
282* function calls over dummy data, by computing additional HMAC updates.
283*
284* The countermeasure was described (in a similar way) in the Lucky 13 paper.
285*
286* Background:
287* - One SHA-1/SHA-256 compression is performed with 64 bytes of data.
288* - HMAC adds 8 byte length field and padding (at least 1 byte) so that we have:
289* - 0 - 55 bytes: 1 compression
290* - 56 - 55+64 bytes: 2 compressions
291* - 56+64 - 55+2*64 bytes: 3 compressions ...
292* - For SHA-384, this works similarly, but we have 128 byte blocks and 16 byte
293* long length field. This results in:
294* - 0 - 111 bytes: 1 compression
295* - 112 - 111+128 bytes: 2 compressions ...
296*
297* The implemented countermeasure works as follows:
298* 1) It computes max_compressions: number of maximum compressions performed on
299* the decrypted data
300* 2) It computes current_compressions: number of compressions performed on the
301* decrypted data, after padding has been removed
302* 3) If current_compressions != max_compressions: It invokes an HMAC update
303* over dummy data so that (max_compressions - current_compressions)
304* compressions are performed. Otherwise, it invokes an HMAC update so that
305* no compressions are performed.
306*
307* Note that the padding validation in Botan is always performed over
308* min(plen,256) bytes, see the function check_tls_cbc_padding. This differs
309* from the countermeasure described in the paper.
310*
311* Note that the padding length padlen does also count the last byte
312* of the decrypted plaintext. This is different from the Lucky 13 paper.
313*
314* This countermeasure leaves a difference of about 100 clock cycles (in
315* comparison to >1000 clock cycles observed without it).
316*
317* plen represents the length of the decrypted plaintext message P
318* padlen represents the padding length
319*
320*/
321void TLS_CBC_HMAC_AEAD_Decryption::perform_additional_compressions(size_t plen, size_t padlen) {
322 uint16_t block_size;
324 if(mac().name() == "HMAC(SHA-384)") {
325 block_size = 128;
327 } else {
328 block_size = 64;
330 }
331 // number of maximum MACed bytes
332 const uint16_t L1 = static_cast<uint16_t>(13 + plen - tag_size());
333 // number of current MACed bytes (L1 - padlen)
334 // Here the Lucky 13 paper is different because the padlen length in the paper
335 // does not count the last message byte.
336 const uint16_t L2 = static_cast<uint16_t>(13 + plen - padlen - tag_size());
337 // From the paper, for SHA-256/SHA-1 compute: ceil((L1-55)/64) and ceil((L2-55)/64)
338 // ceil((L1-55)/64) = floor((L1+64-1-55)/64)
339 // Here we compute number of compressions for SHA-* in general
342 // number of additional compressions we have to perform
345 // We compute the data length we need to achieve the number of compressions.
346 // If there are no compressions, we just add 55/111 dummy bytes so that no
347 // compression is performed.
349 std::vector<uint8_t> data(data_len);
350 mac().update(data);
351 // we do not need to clear the MAC since the connection is broken anyway
352}
353
354void TLS_CBC_HMAC_AEAD_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
355 update(buffer, offset);
356 buffer.resize(offset);
357
358 const size_t record_len = msg().size();
359 uint8_t* record_contents = msg().data();
360
361 // This early exit does not leak info because all the values compared are public
362 if(record_len < tag_size() || (record_len - (use_encrypt_then_mac() ? tag_size() : 0)) % block_size() != 0) {
363 throw TLS_Exception(Alert::BadRecordMac, "Message authentication failure");
364 }
365
367 const size_t enc_size = record_len - tag_size();
368 const size_t enc_iv_size = enc_size + iv_size();
369
371
372 mac().update(assoc_data_with_len(static_cast<uint16_t>(enc_iv_size)));
373 if(iv_size() > 0) {
374 mac().update(cbc_state());
375 }
377
378 std::vector<uint8_t> mac_buf(tag_size());
379 mac().final(mac_buf.data());
380
381 const size_t mac_offset = enc_size;
382
384
385 if(!mac_ok.as_bool()) {
386 throw TLS_Exception(Alert::BadRecordMac, "Message authentication failure");
387 }
388
389 cbc_decrypt_record(record_contents, enc_size);
390
391 // 0 if padding was invalid, otherwise 1 + padding_bytes
393
394 // No oracle here, whoever sent us this had the key since MAC check passed
395 if(pad_size == 0) {
396 throw TLS_Exception(Alert::BadRecordMac, "Message authentication failure");
397 }
398
399 const uint8_t* plaintext_block = &record_contents[0];
400 const size_t plaintext_length = enc_size - pad_size;
401
402 buffer.insert(buffer.end(), plaintext_block, plaintext_block + plaintext_length);
403 } else {
404 cbc_decrypt_record(record_contents, record_len);
405
407
408 // 0 if padding was invalid, otherwise 1 + padding_bytes
410
411 /*
412 This mask is zero if there is not enough room in the packet to get a valid MAC.
413
414 We have to accept empty packets, since otherwise we are not compatible
415 with how OpenSSL's countermeasure for fixing BEAST in TLS 1.0 CBC works
416 (sending empty records, instead of 1/(n-1) splitting)
417 */
418
419 // We know the cast cannot overflow as pad_size <= 256 && tag_size <= 32
420 const auto size_ok_mask =
421 CT::Mask<uint16_t>::is_lte(static_cast<uint16_t>(tag_size() + pad_size), static_cast<uint16_t>(record_len));
422
423 pad_size = size_ok_mask.if_set_return(pad_size);
424
426
427 /*
428 This is unpoisoned sooner than it should. The pad_size leaks to plaintext_length and
429 then to the timing channel in the MAC computation described in the Lucky 13 paper.
430 */
432
433 const uint8_t* plaintext_block = &record_contents[0];
434 const uint16_t plaintext_length = static_cast<uint16_t>(record_len - tag_size() - pad_size);
435
436 mac().update(assoc_data_with_len(plaintext_length));
437 mac().update(plaintext_block, plaintext_length);
438
439 std::vector<uint8_t> mac_buf(tag_size());
440 mac().final(mac_buf.data());
441
442 const size_t mac_offset = record_len - (tag_size() + pad_size);
443
445
447
449
450 if(ok_mask.as_bool()) {
451 buffer.insert(buffer.end(), plaintext_block, plaintext_block + plaintext_length);
452 } else {
453 perform_additional_compressions(record_len, pad_size);
454
455 /*
456 * In DTLS case we have to finish computing the MAC since we require the
457 * MAC state be reset for future packets. This extra timing channel may
458 * be exploitable in a Lucky13 variant.
459 */
461 mac().final(mac_buf);
462 }
463 throw TLS_Exception(Alert::BadRecordMac, "Message authentication failure");
464 }
465 }
466}
467
468} // namespace Botan::TLS
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:98
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:50
void update(const uint8_t in[], size_t length)
Definition buf_comp.h:35
virtual size_t output_length() const =0
void final(uint8_t out[])
Definition buf_comp.h:70
static constexpr Mask< T > is_lte(T x, T y)
Definition ct_utils.h:149
static constexpr Mask< T > expand(T v)
Definition ct_utils.h:115
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:134
static constexpr Mask< T > is_lt(T x, T y)
Definition ct_utils.h:139
void start(std::span< const uint8_t > nonce)
Definition cipher_mode.h:89
size_t process(std::span< uint8_t > msg)
void set_key(const SymmetricKey &key)
Definition sym_algo.h:113
virtual bool has_keying_material() const =0
virtual void clear()=0
size_t output_length(size_t input_length) const override
Definition tls_cbc.cpp:272
void set_associated_data_n(size_t idx, std::span< const uint8_t > ad) override
Definition tls_cbc.cpp:138
size_t output_length(size_t input_length) const override
Definition tls_cbc.cpp:182
size_t update_granularity() const final
Definition tls_cbc.cpp:71
void set_associated_data_n(size_t idx, std::span< const uint8_t > ad) override
Definition tls_cbc.cpp:130
secure_vector< uint8_t > & cbc_state()
Definition tls_cbc.h:75
Key_Length_Specification key_spec() const final
Definition tls_cbc.cpp:86
bool has_keying_material() const final
Definition tls_cbc.cpp:90
size_t ideal_granularity() const final
Definition tls_cbc.cpp:75
std::vector< uint8_t > assoc_data_with_len(uint16_t len)
Definition tls_cbc.cpp:122
std::string name() const final
Definition tls_cbc.cpp:67
std::vector< uint8_t > & assoc_data()
Definition tls_cbc.h:77
secure_vector< uint8_t > & msg()
Definition tls_cbc.h:79
TLS_CBC_HMAC_AEAD_Mode(Cipher_Dir direction, std::unique_ptr< BlockCipher > cipher, std::unique_ptr< MessageAuthenticationCode > mac, size_t cipher_keylen, size_t mac_keylen, Protocol_Version version, bool use_encrypt_then_mac)
Definition tls_cbc.cpp:26
MessageAuthenticationCode & mac() const
Definition tls_cbc.h:70
Cipher_Mode & cbc() const
Definition tls_cbc.h:68
size_t tag_size() const final
Definition tls_cbc.h:37
bool valid_nonce_length(size_t nl) const final
Definition tls_cbc.cpp:79
std::string m_cipher_name
std::string name
int(* update)(CTX *, const void *, CC_LONG len)
void poison(const T *p, size_t n)
Definition ct_utils.h:46
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:345
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:57
uint16_t check_tls_cbc_padding(const uint8_t record[], size_t record_len)
Definition tls_cbc.cpp:233
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:146
size_t round_up(size_t n, size_t align_to)
Definition rounding.h:21
constexpr uint16_t make_uint16(uint8_t i0, uint8_t i1)
Definition loadstor.h:88