Botan 3.11.1
Crypto and TLS for C&
tls_record.cpp
Go to the documentation of this file.
1/*
2* TLS Record Handling
3* (C) 2012,2013,2014,2015,2016,2019 Jack Lloyd
4* 2016 Juraj Somorovsky
5* 2016 Matthias Gierlings
6*
7* Botan is released under the Simplified BSD License (see license.txt)
8*/
9
10#include <botan/internal/tls_record.h>
11
12#include <botan/aead.h>
13#include <botan/block_cipher.h>
14#include <botan/mac.h>
15#include <botan/rng.h>
16#include <botan/tls_ciphersuite.h>
17#include <botan/tls_exceptn.h>
18#include <botan/internal/fmt.h>
19#include <botan/internal/loadstor.h>
20#include <botan/internal/tls_seq_numbers.h>
21#include <botan/internal/tls_session_key.h>
22
23#if defined(BOTAN_HAS_TLS_CBC)
24 #include <botan/internal/tls_cbc.h>
25#endif
26
27#if defined(BOTAN_HAS_TLS_NULL)
28 #include <botan/internal/tls_null.h>
29#endif
30
31namespace Botan::TLS {
32
34
36 Connection_Side side,
37 bool our_side,
38 const Ciphersuite& suite,
39 const Session_Keys& keys,
40 bool uses_encrypt_then_mac) {
41 // NOLINTBEGIN(*-prefer-member-initializer)
42 m_nonce_format = suite.nonce_format();
43 m_nonce_bytes_from_record = suite.nonce_bytes_from_record(version);
44 m_nonce_bytes_from_handshake = suite.nonce_bytes_from_handshake();
45
46 const secure_vector<uint8_t>& aead_key = keys.aead_key(side);
47 m_nonce = keys.nonce(side);
48 // NOLINTEND(*-prefer-member-initializer)
49
50 BOTAN_ASSERT_NOMSG(m_nonce.size() == m_nonce_bytes_from_handshake);
51
53#if defined(BOTAN_HAS_TLS_CBC)
54 // legacy CBC+HMAC mode
55 auto mac = MessageAuthenticationCode::create_or_throw(fmt("HMAC({})", suite.mac_algo()));
56 auto cipher = BlockCipher::create_or_throw(suite.cipher_algo());
57
58 if(our_side) {
59 m_aead = std::make_unique<TLS_CBC_HMAC_AEAD_Encryption>(std::move(cipher),
60 std::move(mac),
61 suite.cipher_keylen(),
62 suite.mac_keylen(),
63 version,
64 uses_encrypt_then_mac);
65 } else {
66 m_aead = std::make_unique<TLS_CBC_HMAC_AEAD_Decryption>(std::move(cipher),
67 std::move(mac),
68 suite.cipher_keylen(),
69 suite.mac_keylen(),
70 version,
71 uses_encrypt_then_mac);
72 }
73
74#else
75 BOTAN_UNUSED(uses_encrypt_then_mac);
76 throw Internal_Error("Negotiated disabled TLS CBC+HMAC ciphersuite");
77#endif
79#if defined(BOTAN_HAS_TLS_NULL)
80 auto mac = MessageAuthenticationCode::create_or_throw(fmt("HMAC({})", suite.mac_algo()));
81
82 if(our_side) {
83 m_aead = std::make_unique<TLS_NULL_HMAC_AEAD_Encryption>(std::move(mac), suite.mac_keylen());
84 } else {
85 m_aead = std::make_unique<TLS_NULL_HMAC_AEAD_Decryption>(std::move(mac), suite.mac_keylen());
86 }
87#else
88 throw Internal_Error("Negotiated disabled TLS NULL ciphersuite");
89#endif
90 } else {
91 m_aead =
93 }
94
95 m_aead->set_key(aead_key);
96}
97
98std::vector<uint8_t> Connection_Cipher_State::aead_nonce(uint64_t seq, RandomNumberGenerator& rng) {
99 switch(m_nonce_format) {
101 return std::vector<uint8_t>{};
102 }
104 if(!m_nonce.empty()) {
105 std::vector<uint8_t> nonce;
106 nonce.swap(m_nonce);
107 return nonce;
108 }
109 std::vector<uint8_t> nonce(nonce_bytes_from_record());
110 rng.randomize(nonce.data(), nonce.size());
111 return nonce;
112 }
114 std::vector<uint8_t> nonce(12);
115 store_be(seq, nonce.data() + 4);
116 xor_buf(nonce, m_nonce.data(), m_nonce.size());
117 return nonce;
118 }
120 BOTAN_ASSERT_NOMSG(m_nonce.size() == 4);
121 std::vector<uint8_t> nonce(12);
122 copy_mem(&nonce[0], m_nonce.data(), 4); // NOLINT(*container-data-pointer)
123 store_be(seq, &nonce[nonce_bytes_from_handshake()]);
124 return nonce;
125 }
126 }
127
128 throw Invalid_State("Unknown nonce format specified");
129}
130
131std::vector<uint8_t> Connection_Cipher_State::aead_nonce(const uint8_t record[], size_t record_len, uint64_t seq) {
132 switch(m_nonce_format) {
134 return std::vector<uint8_t>{};
135 }
137 if(nonce_bytes_from_record() == 0 && !m_nonce.empty()) {
138 std::vector<uint8_t> nonce;
139 nonce.swap(m_nonce);
140 return nonce;
141 }
142 if(record_len < nonce_bytes_from_record()) {
143 throw Decoding_Error("Invalid CBC packet too short to be valid");
144 }
145 std::vector<uint8_t> nonce(record, record + nonce_bytes_from_record());
146 return nonce;
147 }
149 std::vector<uint8_t> nonce(12);
150 store_be(seq, nonce.data() + 4);
151 xor_buf(nonce, m_nonce.data(), m_nonce.size());
152 return nonce;
153 }
155 BOTAN_ASSERT_NOMSG(m_nonce.size() == 4);
156 if(record_len < nonce_bytes_from_record()) {
157 throw Decoding_Error("Invalid AEAD packet too short to be valid");
158 }
159 std::vector<uint8_t> nonce(12);
160 copy_mem(&nonce[0], m_nonce.data(), 4); // NOLINT(*container-data-pointer)
162 return nonce;
163 }
164 }
165
166 throw Invalid_State("Unknown nonce format specified");
167}
168
169std::vector<uint8_t> Connection_Cipher_State::format_ad(uint64_t msg_sequence,
170 Record_Type msg_type,
171 Protocol_Version version,
172 uint16_t msg_length) {
173 std::vector<uint8_t> ad(13);
174
175 store_be(msg_sequence, &ad[0]); // NOLINT(*container-data-pointer)
176 ad[8] = static_cast<uint8_t>(msg_type);
177 ad[9] = version.major_version();
178 ad[10] = version.minor_version();
179 ad[11] = get_byte<0>(msg_length);
180 ad[12] = get_byte<1>(msg_length);
181
182 return ad;
183}
184
185namespace {
186
187inline void append_u16_len(secure_vector<uint8_t>& output, size_t len_field) {
188 const uint16_t len16 = static_cast<uint16_t>(len_field);
189 BOTAN_ASSERT_EQUAL(len_field, len16, "No truncation");
190 output.push_back(get_byte<0>(len16));
191 output.push_back(get_byte<1>(len16));
192}
193
194void write_record_header(secure_vector<uint8_t>& output,
195 Record_Type record_type,
196 Protocol_Version version,
197 uint64_t record_sequence) {
198 output.clear();
199
200 output.push_back(static_cast<uint8_t>(record_type));
201 output.push_back(version.major_version());
202 output.push_back(version.minor_version());
203
204 if(version.is_datagram_protocol()) {
205 for(size_t i = 0; i != 8; ++i) {
206 output.push_back(get_byte_var(i, record_sequence));
207 }
208 }
209}
210
211} // namespace
212
214 Record_Type record_type,
215 Protocol_Version version,
216 uint64_t record_sequence,
217 const uint8_t* message,
218 size_t message_len) {
219 if(record_type == Record_Type::ApplicationData) {
220 throw Internal_Error("Writing an unencrypted TLS application data record");
221 }
222 write_record_header(output, record_type, version, record_sequence);
223 append_u16_len(output, message_len);
224 output.insert(output.end(), message, message + message_len);
225}
226
228 Record_Type record_type,
229 Protocol_Version version,
230 uint64_t record_sequence,
231 const uint8_t* message,
232 size_t message_len,
235 write_record_header(output, record_type, version, record_sequence);
236
237 AEAD_Mode& aead = cs.aead();
238 std::vector<uint8_t> aad = cs.format_ad(record_sequence, record_type, version, static_cast<uint16_t>(message_len));
239
240 const size_t ctext_size = aead.output_length(message_len);
241
242 const size_t rec_size = ctext_size + cs.nonce_bytes_from_record();
243
244 aead.set_associated_data(aad);
245
246 const std::vector<uint8_t> nonce = cs.aead_nonce(record_sequence, rng);
247
248 append_u16_len(output, rec_size);
249
250 if(cs.nonce_bytes_from_record() > 0) {
252 output += nonce;
253 } else {
254 output += std::make_pair(&nonce[cs.nonce_bytes_from_handshake()], cs.nonce_bytes_from_record());
255 }
256 }
257
258 const size_t header_size = output.size();
259 output += std::make_pair(message, message_len);
260
261 aead.start(nonce);
262 aead.finish(output, header_size);
263
264 BOTAN_ASSERT(output.size() < MAX_CIPHERTEXT_SIZE, "Produced ciphertext larger than protocol allows");
265}
266
267namespace {
268
269size_t fill_buffer_to(
270 secure_vector<uint8_t>& readbuf, const uint8_t*& input, size_t& input_size, size_t& input_consumed, size_t desired) {
271 if(readbuf.size() >= desired) {
272 return 0; // already have it
273 }
274
275 const size_t taken = std::min(input_size, desired - readbuf.size());
276
277 readbuf.insert(readbuf.end(), input, input + taken);
278 input_consumed += taken;
279 input_size -= taken;
280 input += taken;
281
282 return (desired - readbuf.size()); // how many bytes do we still need?
283}
284
285void decrypt_record(secure_vector<uint8_t>& output,
286 uint8_t record_contents[],
287 size_t record_len,
288 uint64_t record_sequence,
289 Protocol_Version record_version,
290 Record_Type record_type,
292 AEAD_Mode& aead = cs.aead();
293
294 const std::vector<uint8_t> nonce = cs.aead_nonce(record_contents, record_len, record_sequence);
295 const uint8_t* msg = &record_contents[cs.nonce_bytes_from_record()];
296 const size_t msg_length = record_len - cs.nonce_bytes_from_record();
297
298 /*
299 * This early rejection is based just on public information (length of the
300 * encrypted packet) and so does not leak any information. We used to use
301 * decode_error here which really is more appropriate, but that confuses some
302 * tools which are attempting automated detection of padding oracles,
303 * including older versions of TLS-Attacker.
304 */
305 if(msg_length < aead.minimum_final_size()) {
306 throw TLS_Exception(Alert::BadRecordMac, "AEAD packet is shorter than the tag");
307 }
308
309 const size_t ptext_size = aead.output_length(msg_length);
310
311 aead.set_associated_data(
312 cs.format_ad(record_sequence, record_type, record_version, static_cast<uint16_t>(ptext_size)));
313
314 aead.start(nonce);
315
316 output.assign(msg, msg + msg_length);
317 aead.finish(output, 0);
318}
319
320Record_Header read_tls_record(secure_vector<uint8_t>& readbuf,
321 const uint8_t input[],
322 size_t input_len,
323 size_t& consumed,
325 Connection_Sequence_Numbers* sequence_numbers,
326 const get_cipherstate_fn& get_cipherstate) {
327 if(readbuf.size() < TLS_HEADER_SIZE) {
328 // header incomplete
329 if(const size_t needed = fill_buffer_to(readbuf, input, input_len, consumed, TLS_HEADER_SIZE)) {
330 return Record_Header(needed);
331 }
332
333 BOTAN_ASSERT_EQUAL(readbuf.size(), TLS_HEADER_SIZE, "Have an entire header");
334 }
335
336 /*
337 Verify that the record type and record version are within some expected
338 range, so we can quickly reject totally invalid packets.
339
340 Unfortunately we cannot be more strict about the record number than just
341 checking the major version, at least at this level, due to this requirement
342 in RFC 7568
343
344 TLS servers MUST accept any value {03,XX} (including {03,00}) as
345 the record layer version number for ClientHello
346 */
347 const bool bad_record_type = readbuf[0] < 20 || readbuf[0] > 23;
348 const bool bad_record_version = readbuf[1] != 3;
349
350 if(bad_record_type || bad_record_version) {
351 // We know we read up to at least the 5 byte TLS header
352 const std::string first5 = std::string(reinterpret_cast<const char*>(readbuf.data()), 5);
353
354 if(first5 == "GET /" || first5 == "PUT /" || first5 == "POST " || first5 == "HEAD ") {
355 throw TLS_Exception(Alert::ProtocolVersion, "Client sent plaintext HTTP request instead of TLS handshake");
356 }
357
358 if(first5 == "CONNE") {
359 throw TLS_Exception(Alert::ProtocolVersion,
360 "Client sent plaintext HTTP proxy CONNECT request instead of TLS handshake");
361 }
362
363 if(bad_record_type) {
364 // RFC 5246 Section 6.
365 // If a TLS implementation receives an unexpected record type, it MUST
366 // send an unexpected_message alert.
367 throw TLS_Exception(Alert::UnexpectedMessage, "TLS record type had unexpected value");
368 }
369 throw TLS_Exception(Alert::ProtocolVersion, "TLS record version had unexpected value");
370 }
371
372 const Protocol_Version version(readbuf[1], readbuf[2]);
373
374 if(version.is_datagram_protocol()) {
375 throw TLS_Exception(Alert::ProtocolVersion, "Expected TLS but got a record with DTLS version");
376 }
377
378 const size_t record_size = make_uint16(readbuf[TLS_HEADER_SIZE - 2], readbuf[TLS_HEADER_SIZE - 1]);
379
380 if(record_size > MAX_CIPHERTEXT_SIZE) {
381 throw TLS_Exception(Alert::RecordOverflow, "Received a record that exceeds maximum size");
382 }
383
384 if(record_size == 0) {
385 throw TLS_Exception(Alert::DecodeError, "Received a completely empty record");
386 }
387
388 if(const size_t needed = fill_buffer_to(readbuf, input, input_len, consumed, TLS_HEADER_SIZE + record_size)) {
389 return Record_Header(needed);
390 }
391
392 BOTAN_ASSERT_EQUAL(static_cast<size_t>(TLS_HEADER_SIZE) + record_size, readbuf.size(), "Have the full record");
393
394 const Record_Type type = static_cast<Record_Type>(readbuf[0]);
395
396 uint16_t epoch = 0;
397
398 uint64_t sequence = 0;
399 if(sequence_numbers != nullptr) {
400 sequence = sequence_numbers->next_read_sequence();
401 epoch = sequence_numbers->current_read_epoch();
402 } else {
403 // server initial handshake case
404 epoch = 0;
405 }
406
407 if(epoch == 0) {
408 // Unencrypted initial handshake
409 recbuf.assign(readbuf.begin() + TLS_HEADER_SIZE, readbuf.begin() + TLS_HEADER_SIZE + record_size);
410 readbuf.clear();
411 return Record_Header(sequence, version, type);
412 }
413
414 // Otherwise, decrypt, check MAC, return plaintext
415 auto cs = get_cipherstate(epoch);
416
417 BOTAN_ASSERT(cs, "Have cipherstate for this epoch");
418
419 decrypt_record(recbuf, &readbuf[TLS_HEADER_SIZE], record_size, sequence, version, type, *cs);
420
421 if(sequence_numbers != nullptr) {
422 sequence_numbers->read_accept(sequence);
423 }
424
425 readbuf.clear();
426 return Record_Header(sequence, version, type);
427}
428
429Record_Header read_dtls_record(secure_vector<uint8_t>& readbuf,
430 const uint8_t input[],
431 size_t input_len,
432 size_t& consumed,
434 Connection_Sequence_Numbers* sequence_numbers,
435 const get_cipherstate_fn& get_cipherstate,
436 bool allow_epoch0_restart) {
437 if(readbuf.size() < DTLS_HEADER_SIZE) {
438 // header incomplete
439 if(fill_buffer_to(readbuf, input, input_len, consumed, DTLS_HEADER_SIZE) != 0) {
440 readbuf.clear();
441 return Record_Header(0);
442 }
443
444 BOTAN_ASSERT_EQUAL(readbuf.size(), DTLS_HEADER_SIZE, "Have an entire header");
445 }
446
447 const Protocol_Version version(readbuf[1], readbuf[2]);
448
449 if(version.is_datagram_protocol() == false) {
450 readbuf.clear();
451 return Record_Header(0);
452 }
453
454 const size_t record_size = make_uint16(readbuf[DTLS_HEADER_SIZE - 2], readbuf[DTLS_HEADER_SIZE - 1]);
455
456 if(record_size > MAX_CIPHERTEXT_SIZE) {
457 // Too large to be valid, ignore it
458 readbuf.clear();
459 return Record_Header(0);
460 }
461
462 if(fill_buffer_to(readbuf, input, input_len, consumed, DTLS_HEADER_SIZE + record_size) != 0) {
463 // Truncated packet?
464 readbuf.clear();
465 return Record_Header(0);
466 }
467
468 BOTAN_ASSERT_EQUAL(static_cast<size_t>(DTLS_HEADER_SIZE) + record_size, readbuf.size(), "Have the full record");
469
470 const Record_Type type = static_cast<Record_Type>(readbuf[0]);
471
472 const uint64_t sequence = load_be<uint64_t>(&readbuf[3], 0);
473 const uint16_t epoch = (sequence >> 48);
474
475 const bool already_seen = sequence_numbers != nullptr && sequence_numbers->already_seen(sequence);
476
477 if(already_seen && !(epoch == 0 && allow_epoch0_restart)) {
478 readbuf.clear();
479 return Record_Header(0);
480 }
481
482 if(epoch == 0) {
483 // Unencrypted initial handshake
484 recbuf.assign(readbuf.begin() + DTLS_HEADER_SIZE, readbuf.begin() + DTLS_HEADER_SIZE + record_size);
485 readbuf.clear();
486 if(sequence_numbers != nullptr) {
487 sequence_numbers->read_accept(sequence);
488 }
489 return Record_Header(sequence, version, type);
490 }
491
492 try {
493 // Otherwise, decrypt, check MAC, return plaintext
494 auto cs = get_cipherstate(epoch);
495
496 BOTAN_ASSERT(cs, "Have cipherstate for this epoch");
497
498 decrypt_record(recbuf, &readbuf[DTLS_HEADER_SIZE], record_size, sequence, version, type, *cs);
499 } catch(std::exception&) {
500 readbuf.clear();
501 return Record_Header(0);
502 }
503
504 if(sequence_numbers != nullptr) {
505 sequence_numbers->read_accept(sequence);
506 }
507
508 readbuf.clear();
509 return Record_Header(sequence, version, type);
510}
511
512} // namespace
513
514Record_Header read_record(bool is_datagram,
515 secure_vector<uint8_t>& readbuf,
516 const uint8_t input[],
517 size_t input_len,
518 size_t& consumed,
520 Connection_Sequence_Numbers* sequence_numbers,
521 const get_cipherstate_fn& get_cipherstate,
522 bool allow_epoch0_restart) {
523 if(is_datagram) {
524 return read_dtls_record(
525 readbuf, input, input_len, consumed, recbuf, sequence_numbers, get_cipherstate, allow_epoch0_restart);
526 } else {
527 return read_tls_record(readbuf, input, input_len, consumed, recbuf, sequence_numbers, get_cipherstate);
528 }
529}
530
531} // namespace Botan::TLS
#define BOTAN_UNUSED
Definition assert.h:144
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made)
Definition assert.h:88
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
void set_associated_data(std::span< const uint8_t > ad)
Definition aead.h:59
static std::unique_ptr< AEAD_Mode > create_or_throw(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
Definition aead.cpp:49
static std::unique_ptr< BlockCipher > create_or_throw(std::string_view algo_spec, std::string_view provider="")
void start(std::span< const uint8_t > nonce)
Definition cipher_mode.h:97
void finish(secure_vector< uint8_t > &final_block, size_t offset=0)
virtual size_t output_length(size_t input_length) const =0
static std::unique_ptr< MessageAuthenticationCode > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition mac.cpp:147
void randomize(std::span< uint8_t > output)
Definition rng.h:75
size_t nonce_bytes_from_record(Protocol_Version version) const
Nonce_Format nonce_format() const
size_t nonce_bytes_from_handshake() const
std::string mac_algo() const
std::string cipher_algo() const
Nonce_Format nonce_format() const
Definition tls_record.h:73
size_t nonce_bytes_from_handshake() const
Definition tls_record.h:69
Connection_Cipher_State(Protocol_Version version, Connection_Side which_side, bool is_our_side, const Ciphersuite &suite, const Session_Keys &keys, bool uses_encrypt_then_mac)
std::vector< uint8_t > aead_nonce(uint64_t seq, RandomNumberGenerator &rng)
std::vector< uint8_t > format_ad(uint64_t seq, Record_Type type, Protocol_Version version, uint16_t ptext_length)
uint8_t major_version() const
Definition tls_version.h:84
uint8_t minor_version() const
Definition tls_version.h:89
const std::vector< uint8_t > & nonce(Connection_Side side) const
const secure_vector< uint8_t > & aead_key(Connection_Side side) const
Record_Header read_record(bool is_datagram, secure_vector< uint8_t > &readbuf, const uint8_t input[], size_t input_len, size_t &consumed, secure_vector< uint8_t > &recbuf, Connection_Sequence_Numbers *sequence_numbers, const get_cipherstate_fn &get_cipherstate, bool allow_epoch0_restart)
@ MAX_CIPHERTEXT_SIZE
Definition tls_magic.h:34
@ TLS_HEADER_SIZE
Definition tls_magic.h:26
@ DTLS_HEADER_SIZE
Definition tls_magic.h:27
void write_unencrypted_record(secure_vector< uint8_t > &output, Record_Type record_type, Protocol_Version version, uint64_t record_sequence, const uint8_t *message, size_t message_len)
std::function< std::shared_ptr< Connection_Cipher_State >(uint16_t)> get_cipherstate_fn
Definition tls_record.h:154
void write_record(secure_vector< uint8_t > &output, Record_Type record_type, Protocol_Version version, uint64_t record_sequence, const uint8_t *message, size_t message_len, Connection_Cipher_State &cs, RandomNumberGenerator &rng)
constexpr uint8_t get_byte(T input)
Definition loadstor.h:79
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
constexpr void xor_buf(ranges::contiguous_output_range< uint8_t > auto &&out, ranges::contiguous_range< uint8_t > auto &&in)
Definition mem_ops.h:341
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68
constexpr uint8_t get_byte_var(size_t byte_num, T input)
Definition loadstor.h:69
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:745
constexpr auto load_be(ParamTs &&... params)
Definition loadstor.h:504
constexpr uint16_t make_uint16(uint8_t i0, uint8_t i1)
Definition loadstor.h:92