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