Botan 3.13.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 size_t nonce_from_record = cs.nonce_bytes_from_record();
288 if(record_len <= nonce_from_record) {
289 throw TLS_Exception(Alert::BadRecordMac, "AEAD packet too short to be valid");
290 }
291 const uint8_t* msg = &record_contents[nonce_from_record];
292 const size_t msg_length = record_len - nonce_from_record;
293
294 /*
295 * This early rejection is based just on public information (length of the
296 * encrypted packet) and so does not leak any information. We used to use
297 * decode_error here which really is more appropriate, but that confuses some
298 * tools which are attempting automated detection of padding oracles,
299 * including older versions of TLS-Attacker.
300 */
301 if(msg_length < aead.minimum_final_size()) {
302 throw TLS_Exception(Alert::BadRecordMac, "AEAD packet is shorter than the tag");
303 }
304
305 const size_t ptext_size = aead.output_length(msg_length);
306
307 aead.set_associated_data(
308 cs.format_ad(record_sequence, record_type, record_version, static_cast<uint16_t>(ptext_size)));
309
310 aead.start(nonce);
311
312 output.assign(msg, msg + msg_length);
313 aead.finish(output, 0);
314}
315
316Record_Header read_tls_record(secure_vector<uint8_t>& readbuf,
317 const uint8_t input[],
318 size_t input_len,
319 size_t& consumed,
321 Connection_Sequence_Numbers* sequence_numbers,
322 const get_cipherstate_fn& get_cipherstate) {
323 if(readbuf.size() < TLS_HEADER_SIZE) {
324 // header incomplete
325 if(const size_t needed = fill_buffer_to(readbuf, input, input_len, consumed, TLS_HEADER_SIZE)) {
326 return Record_Header(needed);
327 }
328
329 BOTAN_ASSERT_EQUAL(readbuf.size(), TLS_HEADER_SIZE, "Have an entire header");
330 }
331
332 /*
333 Verify that the record type and record version are within some expected
334 range, so we can quickly reject totally invalid packets.
335
336 Unfortunately we cannot be more strict about the record number than just
337 checking the major version, at least at this level, due to this requirement
338 in RFC 7568
339
340 TLS servers MUST accept any value {03,XX} (including {03,00}) as
341 the record layer version number for ClientHello
342 */
343 const bool bad_record_type = readbuf[0] < 20 || readbuf[0] > 23;
344 const bool bad_record_version = readbuf[1] != 3;
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(const 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. Epoch-0 records are unauthenticated and
480 // deliberately do not advance the replay window: one spoofed record with a
481 // high sequence number would otherwise silently drop every later record
482 // from the real peer. Duplicates are filtered by handshake reassembly.
483 recbuf.assign(readbuf.begin() + DTLS_HEADER_SIZE, readbuf.begin() + DTLS_HEADER_SIZE + record_size);
484 readbuf.clear();
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:53
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:149
void randomize(std::span< uint8_t > output)
Definition rng.h:86
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:38
@ TLS_HEADER_SIZE
Definition tls_magic.h:30
@ DTLS_HEADER_SIZE
Definition tls_magic.h:31
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:403
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128
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