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