Botan 3.12.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/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 std::vector<uint8_t> nonce(nonce_bytes_from_record());
105 rng.randomize(nonce.data(), nonce.size());
106 return nonce;
107 }
109 BOTAN_ASSERT_NOMSG(m_nonce.size() == 12);
110 std::vector<uint8_t> nonce(12);
111 store_be(seq, nonce.data() + 4);
112 xor_buf(nonce, m_nonce.data(), m_nonce.size());
113 return nonce;
114 }
116 BOTAN_ASSERT_NOMSG(m_nonce.size() == 4);
117 std::vector<uint8_t> nonce(12);
118 copy_mem(&nonce[0], m_nonce.data(), 4); // NOLINT(*container-data-pointer)
119 store_be(seq, &nonce[nonce_bytes_from_handshake()]);
120 return nonce;
121 }
122 }
123
124 throw Invalid_State("Unknown nonce format specified");
125}
126
127std::vector<uint8_t> Connection_Cipher_State::aead_nonce(const uint8_t record[], size_t record_len, uint64_t seq) {
128 switch(m_nonce_format) {
130 return std::vector<uint8_t>{};
131 }
133 if(record_len < nonce_bytes_from_record()) {
134 throw Decoding_Error("Invalid CBC packet too short to be valid");
135 }
136 std::vector<uint8_t> nonce(record, record + nonce_bytes_from_record());
137 return nonce;
138 }
140 BOTAN_ASSERT_NOMSG(m_nonce.size() == 12);
141 std::vector<uint8_t> nonce(12);
142 store_be(seq, nonce.data() + 4);
143 xor_buf(nonce, m_nonce.data(), m_nonce.size());
144 return nonce;
145 }
147 BOTAN_ASSERT_NOMSG(m_nonce.size() == 4);
148 if(record_len < nonce_bytes_from_record()) {
149 throw Decoding_Error("Invalid AEAD packet too short to be valid");
150 }
151 std::vector<uint8_t> nonce(12);
152 copy_mem(&nonce[0], m_nonce.data(), 4); // NOLINT(*container-data-pointer)
154 return nonce;
155 }
156 }
157
158 throw Invalid_State("Unknown nonce format specified");
159}
160
161std::vector<uint8_t> Connection_Cipher_State::format_ad(uint64_t msg_sequence,
162 Record_Type msg_type,
163 Protocol_Version version,
164 uint16_t msg_length) {
165 std::vector<uint8_t> ad(13);
166
167 store_be(msg_sequence, &ad[0]); // NOLINT(*container-data-pointer)
168 ad[8] = static_cast<uint8_t>(msg_type);
169 ad[9] = version.major_version();
170 ad[10] = version.minor_version();
171 ad[11] = get_byte<0>(msg_length);
172 ad[12] = get_byte<1>(msg_length);
173
174 return ad;
175}
176
177namespace {
178
179inline void append_u16_len(secure_vector<uint8_t>& output, size_t len_field) {
180 const uint16_t len16 = static_cast<uint16_t>(len_field);
181 BOTAN_ASSERT_EQUAL(len_field, len16, "No truncation");
182 output.push_back(get_byte<0>(len16));
183 output.push_back(get_byte<1>(len16));
184}
185
186void write_record_header(secure_vector<uint8_t>& output,
187 Record_Type record_type,
188 Protocol_Version version,
189 uint64_t record_sequence) {
190 output.clear();
191
192 output.push_back(static_cast<uint8_t>(record_type));
193 output.push_back(version.major_version());
194 output.push_back(version.minor_version());
195
196 if(version.is_datagram_protocol()) {
197 for(size_t i = 0; i != 8; ++i) {
198 output.push_back(get_byte_var(i, record_sequence));
199 }
200 }
201}
202
203} // namespace
204
206 Record_Type record_type,
207 Protocol_Version version,
208 uint64_t record_sequence,
209 const uint8_t* message,
210 size_t message_len) {
211 if(record_type == Record_Type::ApplicationData) {
212 throw Internal_Error("Writing an unencrypted TLS application data record");
213 }
214 write_record_header(output, record_type, version, record_sequence);
215 append_u16_len(output, message_len);
216 output.insert(output.end(), message, message + message_len);
217}
218
220 Record_Type record_type,
221 Protocol_Version version,
222 uint64_t record_sequence,
223 const uint8_t* message,
224 size_t message_len,
227 write_record_header(output, record_type, version, record_sequence);
228
229 AEAD_Mode& aead = cs.aead();
230 std::vector<uint8_t> aad = cs.format_ad(record_sequence, record_type, version, static_cast<uint16_t>(message_len));
231
232 const size_t ctext_size = aead.output_length(message_len);
233
234 const size_t rec_size = ctext_size + cs.nonce_bytes_from_record();
235
236 aead.set_associated_data(aad);
237
238 const std::vector<uint8_t> nonce = cs.aead_nonce(record_sequence, rng);
239
240 append_u16_len(output, rec_size);
241
242 if(cs.nonce_bytes_from_record() > 0) {
244 output += nonce;
245 } else {
246 output += std::make_pair(&nonce[cs.nonce_bytes_from_handshake()], cs.nonce_bytes_from_record());
247 }
248 }
249
250 const size_t header_size = output.size();
251 output += std::make_pair(message, message_len);
252
253 aead.start(nonce);
254 aead.finish(output, header_size);
255
256 BOTAN_ASSERT(output.size() < MAX_CIPHERTEXT_SIZE, "Produced ciphertext larger than protocol allows");
257}
258
259namespace {
260
261size_t fill_buffer_to(
262 secure_vector<uint8_t>& readbuf, const uint8_t*& input, size_t& input_size, size_t& input_consumed, size_t desired) {
263 if(readbuf.size() >= desired) {
264 return 0; // already have it
265 }
266
267 const size_t taken = std::min(input_size, desired - readbuf.size());
268
269 readbuf.insert(readbuf.end(), input, input + taken);
270 input_consumed += taken;
271 input_size -= taken;
272 input += taken;
273
274 return (desired - readbuf.size()); // how many bytes do we still need?
275}
276
277void decrypt_record(secure_vector<uint8_t>& output,
278 uint8_t record_contents[],
279 size_t record_len,
280 uint64_t record_sequence,
281 Protocol_Version record_version,
282 Record_Type record_type,
284 AEAD_Mode& aead = cs.aead();
285
286 const std::vector<uint8_t> nonce = cs.aead_nonce(record_contents, record_len, record_sequence);
287 const uint8_t* msg = &record_contents[cs.nonce_bytes_from_record()];
288 const size_t msg_length = record_len - cs.nonce_bytes_from_record();
289
290 /*
291 * This early rejection is based just on public information (length of the
292 * encrypted packet) and so does not leak any information. We used to use
293 * decode_error here which really is more appropriate, but that confuses some
294 * tools which are attempting automated detection of padding oracles,
295 * including older versions of TLS-Attacker.
296 */
297 if(msg_length < aead.minimum_final_size()) {
298 throw TLS_Exception(Alert::BadRecordMac, "AEAD packet is shorter than the tag");
299 }
300
301 const size_t ptext_size = aead.output_length(msg_length);
302
303 aead.set_associated_data(
304 cs.format_ad(record_sequence, record_type, record_version, static_cast<uint16_t>(ptext_size)));
305
306 aead.start(nonce);
307
308 output.assign(msg, msg + msg_length);
309 aead.finish(output, 0);
310}
311
312Record_Header read_tls_record(secure_vector<uint8_t>& readbuf,
313 const uint8_t input[],
314 size_t input_len,
315 size_t& consumed,
317 Connection_Sequence_Numbers* sequence_numbers,
318 const get_cipherstate_fn& get_cipherstate) {
319 if(readbuf.size() < TLS_HEADER_SIZE) {
320 // header incomplete
321 if(const size_t needed = fill_buffer_to(readbuf, input, input_len, consumed, TLS_HEADER_SIZE)) {
322 return Record_Header(needed);
323 }
324
325 BOTAN_ASSERT_EQUAL(readbuf.size(), TLS_HEADER_SIZE, "Have an entire header");
326 }
327
328 /*
329 Verify that the record type and record version are within some expected
330 range, so we can quickly reject totally invalid packets.
331
332 Unfortunately we cannot be more strict about the record number than just
333 checking the major version, at least at this level, due to this requirement
334 in RFC 7568
335
336 TLS servers MUST accept any value {03,XX} (including {03,00}) as
337 the record layer version number for ClientHello
338 */
339 const bool bad_record_type = readbuf[0] < 20 || readbuf[0] > 23;
340 const bool bad_record_version = readbuf[1] != 3;
341
342 if(bad_record_type || bad_record_version) {
343 // We know we read up to at least the 5 byte TLS header
344 const std::string first5 = std::string(reinterpret_cast<const char*>(readbuf.data()), 5);
345
346 if(first5 == "GET /" || first5 == "PUT /" || first5 == "POST " || first5 == "HEAD ") {
347 throw TLS_Exception(Alert::ProtocolVersion, "Client sent plaintext HTTP request instead of TLS handshake");
348 }
349
350 if(first5 == "CONNE") {
351 throw TLS_Exception(Alert::ProtocolVersion,
352 "Client sent plaintext HTTP proxy CONNECT request instead of TLS handshake");
353 }
354
355 if(bad_record_type) {
356 // RFC 5246 Section 6.
357 // If a TLS implementation receives an unexpected record type, it MUST
358 // send an unexpected_message alert.
359 throw TLS_Exception(Alert::UnexpectedMessage, "TLS record type had unexpected value");
360 }
361 throw TLS_Exception(Alert::ProtocolVersion, "TLS record version had unexpected value");
362 }
363
364 const Protocol_Version version(readbuf[1], readbuf[2]);
365
366 if(version.is_datagram_protocol()) {
367 throw TLS_Exception(Alert::ProtocolVersion, "Expected TLS but got a record with DTLS version");
368 }
369
370 const size_t record_size = make_uint16(readbuf[TLS_HEADER_SIZE - 2], readbuf[TLS_HEADER_SIZE - 1]);
371
372 if(record_size > MAX_CIPHERTEXT_SIZE) {
373 throw TLS_Exception(Alert::RecordOverflow, "Received a record that exceeds maximum size");
374 }
375
376 if(record_size == 0) {
377 throw TLS_Exception(Alert::DecodeError, "Received a completely empty record");
378 }
379
380 if(const size_t needed = fill_buffer_to(readbuf, input, input_len, consumed, TLS_HEADER_SIZE + record_size)) {
381 return Record_Header(needed);
382 }
383
384 BOTAN_ASSERT_EQUAL(static_cast<size_t>(TLS_HEADER_SIZE) + record_size, readbuf.size(), "Have the full record");
385
386 const Record_Type type = static_cast<Record_Type>(readbuf[0]);
387
388 uint16_t epoch = 0;
389
390 uint64_t sequence = 0;
391 if(sequence_numbers != nullptr) {
392 sequence = sequence_numbers->next_read_sequence();
393 epoch = sequence_numbers->current_read_epoch();
394 } else {
395 // server initial handshake case
396 epoch = 0;
397 }
398
399 if(epoch == 0) {
400 // Unencrypted initial handshake
401 recbuf.assign(readbuf.begin() + TLS_HEADER_SIZE, readbuf.begin() + TLS_HEADER_SIZE + record_size);
402 readbuf.clear();
403 return Record_Header(sequence, version, type);
404 }
405
406 // Otherwise, decrypt, check MAC, return plaintext
407 auto cs = get_cipherstate(epoch);
408
409 BOTAN_ASSERT(cs, "Have cipherstate for this epoch");
410
411 decrypt_record(recbuf, &readbuf[TLS_HEADER_SIZE], record_size, sequence, version, type, *cs);
412
413 if(sequence_numbers != nullptr) {
414 sequence_numbers->read_accept(sequence);
415 }
416
417 readbuf.clear();
418 return Record_Header(sequence, version, type);
419}
420
421Record_Header read_dtls_record(secure_vector<uint8_t>& readbuf,
422 const uint8_t input[],
423 size_t input_len,
424 size_t& consumed,
426 Connection_Sequence_Numbers* sequence_numbers,
427 const get_cipherstate_fn& get_cipherstate,
428 bool allow_epoch0_restart) {
429 if(readbuf.size() < DTLS_HEADER_SIZE) {
430 // header incomplete
431 if(fill_buffer_to(readbuf, input, input_len, consumed, DTLS_HEADER_SIZE) != 0) {
432 readbuf.clear();
433 return Record_Header(0);
434 }
435
436 BOTAN_ASSERT_EQUAL(readbuf.size(), DTLS_HEADER_SIZE, "Have an entire header");
437 }
438
439 const Protocol_Version version(readbuf[1], readbuf[2]);
440
441 if(version.is_datagram_protocol() == false) {
442 readbuf.clear();
443 return Record_Header(0);
444 }
445
446 const size_t record_size = make_uint16(readbuf[DTLS_HEADER_SIZE - 2], readbuf[DTLS_HEADER_SIZE - 1]);
447
448 if(record_size > MAX_CIPHERTEXT_SIZE) {
449 // Too large to be valid, ignore it
450 readbuf.clear();
451 return Record_Header(0);
452 }
453
454 if(fill_buffer_to(readbuf, input, input_len, consumed, DTLS_HEADER_SIZE + record_size) != 0) {
455 // Truncated packet?
456 readbuf.clear();
457 return Record_Header(0);
458 }
459
460 BOTAN_ASSERT_EQUAL(static_cast<size_t>(DTLS_HEADER_SIZE) + record_size, readbuf.size(), "Have the full record");
461
462 const Record_Type type = static_cast<Record_Type>(readbuf[0]);
463
464 const uint64_t sequence = load_be<uint64_t>(&readbuf[3], 0);
465 const uint16_t epoch = (sequence >> 48);
466
467 const bool already_seen = sequence_numbers != nullptr && sequence_numbers->already_seen(sequence);
468
469 if(already_seen && !(epoch == 0 && allow_epoch0_restart)) {
470 readbuf.clear();
471 return Record_Header(0);
472 }
473
474 if(epoch == 0) {
475 // Unencrypted initial handshake
476 recbuf.assign(readbuf.begin() + DTLS_HEADER_SIZE, readbuf.begin() + DTLS_HEADER_SIZE + record_size);
477 readbuf.clear();
478 if(sequence_numbers != nullptr) {
479 sequence_numbers->read_accept(sequence);
480 }
481 return Record_Header(sequence, version, type);
482 }
483
484 try {
485 // Otherwise, decrypt, check MAC, return plaintext
486 auto cs = get_cipherstate(epoch);
487
488 BOTAN_ASSERT(cs, "Have cipherstate for this epoch");
489
490 decrypt_record(recbuf, &readbuf[DTLS_HEADER_SIZE], record_size, sequence, version, type, *cs);
491 } catch(std::exception&) {
492 readbuf.clear();
493 return Record_Header(0);
494 }
495
496 if(sequence_numbers != nullptr) {
497 sequence_numbers->read_accept(sequence);
498 }
499
500 readbuf.clear();
501 return Record_Header(sequence, version, type);
502}
503
504} // namespace
505
506Record_Header read_record(bool is_datagram,
507 secure_vector<uint8_t>& readbuf,
508 const uint8_t input[],
509 size_t input_len,
510 size_t& consumed,
512 Connection_Sequence_Numbers* sequence_numbers,
513 const get_cipherstate_fn& get_cipherstate,
514 bool allow_epoch0_restart) {
515 if(is_datagram) {
516 return read_dtls_record(
517 readbuf, input, input_len, consumed, recbuf, sequence_numbers, get_cipherstate, allow_epoch0_restart);
518 } else {
519 return read_tls_record(readbuf, input, input_len, consumed, recbuf, sequence_numbers, get_cipherstate);
520 }
521}
522
523} // 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
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
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