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