Botan 3.12.0
Crypto and TLS for C&
tls_cipher_state.cpp
Go to the documentation of this file.
1/*
2* TLS cipher state implementation for TLS 1.3
3* (C) 2022 Jack Lloyd
4* 2022 Hannes Rantzsch, René Meusel - neXenio GmbH
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9/**
10 * Cipher_State state machine adapted from RFC 8446 7.1.
11 *
12 * 0
13 * |
14 * v
15 * PSK -> HKDF-Extract = Early Secret
16 * |
17 * +-----> Derive-Secret(., "ext binder" | "res binder" | "imp binder", "")
18 * | = binder_key
19 * STATE PSK BINDER
20 * This state is reached by constructing the Cipher_State using init_with_psk().
21 * The state can then be further advanced using advance_with_client_hello() once
22 * the initial Client Hello is fully generated.
23 * |
24 * +-----> Derive-Secret(., "c e traffic", ClientHello)
25 * | = client_early_traffic_secret
26 * |
27 * +-----> Derive-Secret(., "e exp master", ClientHello)
28 * | = early_exporter_master_secret
29 * v
30 * Derive-Secret(., "derived", "")
31 * |
32 * *
33 * STATE EARLY TRAFFIC
34 * This state is reached by calling advance_with_client_hello().
35 * In this state the early data traffic secrets are available. TODO: implement early data.
36 * The state can then be further advanced using advance_with_server_hello().
37 * *
38 * |
39 * v
40 * (EC)DHE -> HKDF-Extract = Handshake Secret
41 * |
42 * +-----> Derive-Secret(., "c hs traffic",
43 * | ClientHello...ServerHello)
44 * | = client_handshake_traffic_secret
45 * |
46 * +-----> Derive-Secret(., "s hs traffic",
47 * | ClientHello...ServerHello)
48 * | = server_handshake_traffic_secret
49 * v
50 * Derive-Secret(., "derived", "")
51 * |
52 * *
53 * STATE HANDSHAKE TRAFFIC
54 * This state is reached by constructing Cipher_State using init_with_server_hello() or
55 * advance_with_server_hello(). In this state the handshake traffic secrets are available.
56 * The state can then be further advanced using advance_with_server_finished().
57 * *
58 * |
59 * v
60 * 0 -> HKDF-Extract = Master Secret
61 * |
62 * +-----> Derive-Secret(., "c ap traffic",
63 * | ClientHello...server Finished)
64 * | = client_application_traffic_secret_0
65 * |
66 * +-----> Derive-Secret(., "s ap traffic",
67 * | ClientHello...server Finished)
68 * | = server_application_traffic_secret_0
69 * |
70 * +-----> Derive-Secret(., "exp master",
71 * | ClientHello...server Finished)
72 * | = exporter_master_secret
73 * *
74 * STATE SERVER APPLICATION TRAFFIC
75 * This state is reached by calling advance_with_server_finished(). It allows the server
76 * to send application traffic and the client to receive it. The opposite direction is not
77 * yet possible in this state. The state can then be further advanced using
78 * advance_with_client_finished().
79 * *
80 * |
81 * +-----> Derive-Secret(., "res master",
82 * ClientHello...client Finished)
83 * = resumption_master_secret
84 * STATE COMPLETED
85 * Once this state is reached the handshake is finished, both client and server can exchange
86 * application data and no further cipher state advances are possible.
87 */
88
89#include <limits>
90#include <utility>
91
92#include <botan/internal/tls_cipher_state.h>
93
94#include <botan/aead.h>
95#include <botan/assert.h>
96#include <botan/hash.h>
97#include <botan/secmem.h>
98#include <botan/tls_ciphersuite.h>
99#include <botan/tls_magic.h>
100
101#include <botan/internal/fmt.h>
102#include <botan/internal/hkdf.h>
103#include <botan/internal/hmac.h>
104#include <botan/internal/loadstor.h>
105#include <botan/internal/tls_channel_impl_13.h>
106
107namespace Botan::TLS {
108
109namespace {
110// RFC 8446 5.3
111// Each AEAD algorithm will specify a range of possible lengths for the
112// per-record nonce, from N_MIN bytes to N_MAX bytes of input [RFC5116].
113// The length of the TLS per-record nonce (iv_length) is set to the
114// larger of 8 bytes and N_MIN for the AEAD algorithm (see [RFC5116],
115// Section 4).
116//
117// N_MIN is 12 for AES_GCM and AES_CCM as per RFC 5116 and also 12 for ChaCha20 per RFC 8439.
118constexpr size_t NONCE_LENGTH = 12;
119} // namespace
120
121std::unique_ptr<Cipher_State> Cipher_State::init_with_server_hello(const Connection_Side side,
122 secure_vector<uint8_t>&& shared_secret,
123 const Ciphersuite& cipher,
124 const Transcript_Hash& transcript_hash,
125 const Secret_Logger& logger) {
126 auto cs = std::unique_ptr<Cipher_State>(new Cipher_State(side, cipher.prf_algo()));
127 cs->advance_without_psk();
128 cs->advance_with_server_hello(cipher, std::move(shared_secret), transcript_hash, logger);
129 return cs;
130}
131
132std::unique_ptr<Cipher_State> Cipher_State::init_with_psk(const Connection_Side side,
133 const Cipher_State::PSK_Type type,
135 std::string_view prf_algo) {
136 auto cs = std::unique_ptr<Cipher_State>(new Cipher_State(side, prf_algo));
137 cs->advance_with_psk(type, std::move(psk));
138 return cs;
139}
140
141void Cipher_State::advance_with_client_hello(const Transcript_Hash& transcript_hash, const Secret_Logger& logger) {
142 BOTAN_ASSERT_NOMSG(m_state == State::PskBinder);
143
144 zap(m_binder_key);
145
146 // TODO: Currently 0-RTT is not yet implemented, hence we don't derive the
147 // early traffic secret for now.
148 //
149 // const auto client_early_traffic_secret = derive_secret(m_early_secret, "c e traffic", transcript_hash);
150 // derive_write_traffic_key(client_early_traffic_secret);
151
152 m_exporter_master_secret = derive_secret(m_early_secret, "e exp master", transcript_hash);
153
154 // draft-thomson-tls-keylogfile-00 Section 3.1
155 // An implementation of TLS 1.3 use the label
156 // "EARLY_EXPORTER_MASTER_SECRET" to identify the secret that is using for
157 // early exporters
158 logger.maybe_log_secret("EARLY_EXPORTER_MASTER_SECRET", m_exporter_master_secret);
159
160 m_salt = derive_secret(m_early_secret, "derived", empty_hash());
161 zap(m_early_secret);
162
163 m_state = State::EarlyTraffic;
164}
165
167 BOTAN_ASSERT_NOMSG(m_state == State::HandshakeTraffic);
168
169 const auto master_secret = hkdf_extract(secure_vector<uint8_t>(m_hash->output_length(), 0x00));
170
171 auto client_application_traffic_secret = derive_secret(master_secret, "c ap traffic", transcript_hash);
172 auto server_application_traffic_secret = derive_secret(master_secret, "s ap traffic", transcript_hash);
173
174 // draft-thomson-tls-keylogfile-00 Section 3.1
175 // An implementation of TLS 1.3 use the label "CLIENT_TRAFFIC_SECRET_0"
176 // and "SERVER_TRAFFIC_SECRET_0" to identify the secrets are using to
177 // protect the connection.
178 logger.maybe_log_secret("CLIENT_TRAFFIC_SECRET_0", client_application_traffic_secret);
179 logger.maybe_log_secret("SERVER_TRAFFIC_SECRET_0", server_application_traffic_secret);
180
181 // Note: the secrets for processing client's application data
182 // are not derived before the client's Finished message
183 // was seen and the handshake can be considered finished.
184 if(m_connection_side == Connection_Side::Server) {
185 derive_write_traffic_key(server_application_traffic_secret);
186 m_read_application_traffic_secret = std::move(client_application_traffic_secret);
187 m_write_application_traffic_secret = std::move(server_application_traffic_secret);
188 } else {
189 derive_read_traffic_key(server_application_traffic_secret);
190 m_read_application_traffic_secret = std::move(server_application_traffic_secret);
191 m_write_application_traffic_secret = std::move(client_application_traffic_secret);
192 }
193
194 m_exporter_master_secret = derive_secret(master_secret, "exp master", transcript_hash);
195
196 // draft-thomson-tls-keylogfile-00 Section 3.1
197 // An implementation of TLS 1.3 use the label "EXPORTER_SECRET" to
198 // identify the secret that is used in generating exporters(rfc8446
199 // Section 7.5).
200 logger.maybe_log_secret("EXPORTER_SECRET", m_exporter_master_secret);
201
202 m_state = State::ServerApplicationTraffic;
203}
204
206 BOTAN_ASSERT_NOMSG(m_state == State::ServerApplicationTraffic);
207
208 zap(m_finished_key);
209 zap(m_peer_finished_key);
210
211 // With the client's Finished message, the handshake is complete and
212 // we can process client application data.
213 if(m_connection_side == Connection_Side::Server) {
214 derive_read_traffic_key(m_read_application_traffic_secret);
215 } else {
216 derive_write_traffic_key(m_write_application_traffic_secret);
217 }
218
219 const auto master_secret = hkdf_extract(secure_vector<uint8_t>(m_hash->output_length(), 0x00));
220
221 m_resumption_master_secret = derive_secret(master_secret, "res master", transcript_hash);
222
223 // This was the final state change; the salt is no longer needed.
224 zap(m_salt);
225
226 m_state = State::Completed;
227}
228
229namespace {
230
231auto current_nonce(const uint64_t seq_no, std::span<const uint8_t> iv) {
232 // RFC 8446 5.3
233 // The per-record nonce for the AEAD construction is formed as follows:
234 //
235 // 1. The 64-bit record sequence number is encoded in network byte
236 // order and padded to the left with zeros to iv_length.
237 //
238 // 2. The padded sequence number is XORed with either the static
239 // client_write_iv or server_write_iv (depending on the role).
240 std::array<uint8_t, NONCE_LENGTH> nonce{};
241 store_be(std::span{nonce}.last<sizeof(seq_no)>(), seq_no);
242 xor_buf(nonce, iv);
243 return nonce;
244}
245
246} // namespace
247
248uint64_t Cipher_State::encrypt_record_fragment(const std::vector<uint8_t>& header, secure_vector<uint8_t>& fragment) {
249 BOTAN_ASSERT_NONNULL(m_encrypt);
250
251 // RFC 8446 5.3
252 // Sequence numbers MUST NOT wrap.
253 if(m_write_seq_no == std::numeric_limits<uint64_t>::max()) {
254 throw Invalid_State("TLS write sequence number overflow");
255 }
256
257 m_encrypt->set_associated_data(header);
258 m_encrypt->start(current_nonce(m_write_seq_no, m_write_iv));
259 m_encrypt->finish(fragment);
260
261 return m_write_seq_no++;
262}
263
264uint64_t Cipher_State::decrypt_record_fragment(const std::vector<uint8_t>& header,
265 secure_vector<uint8_t>& encrypted_fragment) {
266 BOTAN_ASSERT_NONNULL(m_decrypt);
267 BOTAN_ARG_CHECK(encrypted_fragment.size() >= m_decrypt->minimum_final_size(), "fragment too short to decrypt");
268
269 // RFC 8446 5.3
270 // Sequence numbers MUST NOT wrap.
271 if(m_read_seq_no == std::numeric_limits<uint64_t>::max()) {
272 throw Invalid_State("TLS read sequence number overflow");
273 }
274
275 m_decrypt->set_associated_data(header);
276 m_decrypt->start(current_nonce(m_read_seq_no, m_read_iv));
277
278 m_decrypt->finish(encrypted_fragment);
279
280 return m_read_seq_no++;
281}
282
283size_t Cipher_State::encrypt_output_length(const size_t input_length) const {
284 BOTAN_ASSERT_NONNULL(m_encrypt);
285 return m_encrypt->output_length(input_length);
286}
287
288size_t Cipher_State::decrypt_output_length(const size_t input_length) const {
289 BOTAN_ASSERT_NONNULL(m_decrypt);
290 return m_decrypt->output_length(input_length);
291}
292
294 BOTAN_ASSERT_NONNULL(m_decrypt);
295 return m_decrypt->minimum_final_size();
296}
297
299 // Client side:
300 // After successfully receiving a Server Hello we expect servers to send
301 // alerts as protected records only, just like they start protecting their
302 // handshake data at this point.
303 if(m_connection_side == Connection_Side::Client && m_state == State::EarlyTraffic) {
304 return true;
305 }
306
307 // Server side:
308 // Servers must expect clients to send unprotected alerts during the hand-
309 // shake. In particular, in the response to the server's first protected
310 // flight. We don't expect the client to send alerts protected under the
311 // early traffic secret.
312 //
313 // TODO: when implementing PSK and/or early data for the server, we might
314 // need to reconsider this decision.
315 if(m_connection_side == Connection_Side::Server &&
316 (m_state == State::HandshakeTraffic || m_state == State::ServerApplicationTraffic)) {
317 return true;
318 }
319
320 return false;
321}
322
324 // TODO: when implementing early traffic (0-RTT) this will likely need
325 // to allow `State::EarlyTraffic`.
326
327 if(m_connection_side == Connection_Side::Client && m_state != State::Completed) {
328 return false;
329 }
330
331 if(m_connection_side == Connection_Side::Server && m_state != State::ServerApplicationTraffic &&
332 m_state != State::Completed) {
333 return false;
334 }
335
336 return !m_write_key.empty() && !m_write_iv.empty();
337}
338
340 // TODO: when implementing early traffic (0-RTT) this will likely need
341 // to allow `State::EarlyTraffic`.
342
343 if(m_connection_side == Connection_Side::Client && m_state != State::ServerApplicationTraffic &&
344 m_state != State::Completed) {
345 return false;
346 }
347
348 if(m_connection_side == Connection_Side::Server && m_state != State::Completed) {
349 return false;
350 }
351
352 return !m_read_key.empty() && !m_read_iv.empty();
353}
354
355std::string Cipher_State::hash_algorithm() const {
356 BOTAN_ASSERT_NONNULL(m_hash);
357 return m_hash->name();
358}
359
361 if(!cipher.usable_in_version(Protocol_Version::TLS_V13)) {
362 return false;
363 }
364
365 if(hash_algorithm() != cipher.prf_algo()) {
366 return false;
367 }
368
369 BOTAN_ASSERT_NOMSG((m_encrypt == nullptr) == (m_decrypt == nullptr));
370 // Compare canonical AEAD names rather than substring-matching cipher_algo
371 // against m_encrypt->name(). starts_with() is both too permissive (an
372 // AES-128/CCM-8 instance starts with "AES-128/CCM" so it would accept the
373 // CCM-16 suite) and too restrictive (cipher_algo "AES-128/CCM(8)" does not
374 // prefix the canonical "AES-128/CCM(8,3)"). Re-instantiating the AEAD from
375 // cipher_algo yields the same canonical name() the suite would produce.
376 if(m_encrypt) {
377 auto canonical = AEAD_Mode::create(cipher.cipher_algo(), Cipher_Dir::Encryption);
378 if(!canonical || canonical->name() != m_encrypt->name()) {
379 return false;
380 }
381 }
382
383 return true;
384}
385
386std::vector<uint8_t> Cipher_State::psk_binder_mac(
387 const Transcript_Hash& transcript_hash_with_truncated_client_hello) const {
388 BOTAN_ASSERT_NOMSG(m_state == State::PskBinder);
389
390 auto hmac = HMAC(m_hash->new_object());
391 hmac.set_key(m_binder_key);
392 hmac.update(transcript_hash_with_truncated_client_hello);
393 return hmac.final_stdvec();
394}
395
396std::vector<uint8_t> Cipher_State::finished_mac(const Transcript_Hash& transcript_hash) const {
397 BOTAN_ASSERT_NOMSG(m_connection_side != Connection_Side::Server || m_state == State::HandshakeTraffic);
398 BOTAN_ASSERT_NOMSG(m_connection_side != Connection_Side::Client || m_state == State::ServerApplicationTraffic);
399 BOTAN_ASSERT_NOMSG(!m_finished_key.empty());
400
401 auto hmac = HMAC(m_hash->new_object());
402 hmac.set_key(m_finished_key);
403 hmac.update(transcript_hash);
404 return hmac.final_stdvec();
405}
406
408 const std::vector<uint8_t>& peer_mac) const {
409 BOTAN_ASSERT_NOMSG(m_connection_side != Connection_Side::Server || m_state == State::ServerApplicationTraffic);
410 BOTAN_ASSERT_NOMSG(m_connection_side != Connection_Side::Client || m_state == State::HandshakeTraffic);
411 BOTAN_ASSERT_NOMSG(!m_peer_finished_key.empty());
412
413 auto hmac = HMAC(m_hash->new_object());
414 hmac.set_key(m_peer_finished_key);
415 hmac.update(transcript_hash);
416 return hmac.verify_mac(peer_mac);
417}
418
420 BOTAN_ASSERT_NOMSG(m_state == State::Completed);
421
422 return derive_secret(m_resumption_master_secret, "resumption", nonce.get());
423}
424
426 BOTAN_STATE_CHECK(m_state == State::Completed);
427 if(m_ticket_nonce_exhausted) {
428 throw Botan::Invalid_State("ticket nonce pool exhausted");
429 }
430
431 auto retval = store_be<Ticket_Nonce>(m_ticket_nonce);
432
433 if(m_ticket_nonce == std::numeric_limits<decltype(m_ticket_nonce)>::max()) {
434 m_ticket_nonce_exhausted = true;
435 } else {
436 ++m_ticket_nonce;
437 }
438
439 return retval;
440}
441
442secure_vector<uint8_t> Cipher_State::export_key(std::string_view label, std::string_view context, size_t length) const {
444
445 m_hash->update(context);
446 const auto context_hash = m_hash->final_stdvec();
447 return hkdf_expand_label(
448 derive_secret(m_exporter_master_secret, label, empty_hash()), "exporter", context_hash, length);
449}
450
451namespace {
452
453std::unique_ptr<MessageAuthenticationCode> create_hmac(std::string_view hash) {
454 return std::make_unique<HMAC>(HashFunction::create_or_throw(hash));
455}
456
457} // namespace
458
459Cipher_State::Cipher_State(Connection_Side whoami, std::string_view hash_function) :
460 m_state(State::Uninitialized),
461 m_connection_side(whoami),
462 m_extract(std::make_unique<HKDF_Extract>(create_hmac(hash_function))),
463 m_expand(std::make_unique<HKDF_Expand>(create_hmac(hash_function))),
464 m_hash(HashFunction::create_or_throw(hash_function)),
465 m_salt(m_hash->output_length(), 0x00),
466 m_write_seq_no(0),
467 m_read_seq_no(0),
468 m_write_key_update_count(0),
469 m_read_key_update_count(0),
470 m_ticket_nonce(0) {}
471
473
474void Cipher_State::advance_without_psk() {
475 BOTAN_ASSERT_NOMSG(m_state == State::Uninitialized);
476
477 // We are not using `m_early_secret` here because the secret won't be needed
478 // in any further state advancement methods.
479 const auto early_secret = hkdf_extract(secure_vector<uint8_t>(m_hash->output_length(), 0x00));
480 m_salt = derive_secret(early_secret, "derived", empty_hash());
481
482 // Without PSK we skip the `PskBinder` state and go right to `EarlyTraffic`.
483 m_state = State::EarlyTraffic;
484}
485
486void Cipher_State::advance_with_psk(PSK_Type type, secure_vector<uint8_t>&& psk) {
487 BOTAN_ASSERT_NOMSG(m_state == State::Uninitialized);
488
489 m_early_secret = hkdf_extract(std::move(psk));
490
491 // RFC 8446 and RFC 9258 specify these strings
492 const char* binder_label = [type]() -> const char* {
493 switch(type) {
495 return "res binder";
497 return "ext binder";
499 return "imp binder";
500 }
502 }();
503
504 // RFC 8446 4.2.11.2
505 // The PskBinderEntry is computed in the same way as the Finished message
506 // [...] but with the BaseKey being the binder_key derived via the key
507 // schedule from the corresponding PSK which is being offered.
508 //
509 // Hence we are doing the binder key derivation and expansion in one go.
510 const auto binder_key = derive_secret(m_early_secret, binder_label, empty_hash());
511 m_binder_key = hkdf_expand_label(binder_key, "finished", {}, m_hash->output_length());
512
513 m_state = State::PskBinder;
514}
515
517 secure_vector<uint8_t>&& shared_secret,
518 const Transcript_Hash& transcript_hash,
519 const Secret_Logger& logger) {
520 BOTAN_ASSERT_NOMSG(m_state == State::EarlyTraffic);
521 BOTAN_ASSERT_NOMSG(!m_encrypt);
522 BOTAN_ASSERT_NOMSG(!m_decrypt);
524
527
528 const auto handshake_secret = hkdf_extract(std::move(shared_secret));
529
530 const auto client_handshake_traffic_secret = derive_secret(handshake_secret, "c hs traffic", transcript_hash);
531 const auto server_handshake_traffic_secret = derive_secret(handshake_secret, "s hs traffic", transcript_hash);
532
533 // draft-thomson-tls-keylogfile-00 Section 3.1
534 // An implementation of TLS 1.3 use the label
535 // "CLIENT_HANDSHAKE_TRAFFIC_SECRET" and "SERVER_HANDSHAKE_TRAFFIC_SECRET"
536 // to identify the secrets are using to protect handshake messages.
537 logger.maybe_log_secret("CLIENT_HANDSHAKE_TRAFFIC_SECRET", client_handshake_traffic_secret);
538 logger.maybe_log_secret("SERVER_HANDSHAKE_TRAFFIC_SECRET", server_handshake_traffic_secret);
539
540 if(m_connection_side == Connection_Side::Server) {
541 derive_read_traffic_key(client_handshake_traffic_secret, true);
542 derive_write_traffic_key(server_handshake_traffic_secret, true);
543 } else {
544 derive_read_traffic_key(server_handshake_traffic_secret, true);
545 derive_write_traffic_key(client_handshake_traffic_secret, true);
546 }
547
548 m_salt = derive_secret(handshake_secret, "derived", empty_hash());
549
550 m_state = State::HandshakeTraffic;
551}
552
553void Cipher_State::derive_write_traffic_key(const secure_vector<uint8_t>& traffic_secret,
554 const bool handshake_traffic_secret) {
555 BOTAN_ASSERT_NONNULL(m_encrypt);
556
557 m_write_key = hkdf_expand_label(traffic_secret, "key", {}, m_encrypt->minimum_keylength());
558 m_write_iv = hkdf_expand_label(traffic_secret, "iv", {}, NONCE_LENGTH);
559 m_write_seq_no = 0;
560
561 m_encrypt->set_key(m_write_key);
562
563 if(handshake_traffic_secret) {
564 // Key derivation for the MAC in the "Finished" handshake message as described in RFC 8446 4.4.4
565 // (will be cleared in advance_with_server_finished())
566 m_finished_key = hkdf_expand_label(traffic_secret, "finished", {}, m_hash->output_length());
567 }
568}
569
570void Cipher_State::derive_read_traffic_key(const secure_vector<uint8_t>& traffic_secret,
571 const bool handshake_traffic_secret) {
572 BOTAN_ASSERT_NONNULL(m_decrypt);
573
574 m_read_key = hkdf_expand_label(traffic_secret, "key", {}, m_decrypt->minimum_keylength());
575 m_read_iv = hkdf_expand_label(traffic_secret, "iv", {}, NONCE_LENGTH);
576 m_read_seq_no = 0;
577
578 m_decrypt->set_key(m_read_key);
579
580 if(handshake_traffic_secret) {
581 // Key derivation for the MAC in the "Finished" handshake message as described in RFC 8446 4.4.4
582 // (will be cleared in advance_with_client_finished())
583 m_peer_finished_key = hkdf_expand_label(traffic_secret, "finished", {}, m_hash->output_length());
584 }
585}
586
587secure_vector<uint8_t> Cipher_State::hkdf_extract(std::span<const uint8_t> ikm) const {
588 return m_extract->derive_key(m_hash->output_length(), ikm, m_salt, std::vector<uint8_t>());
589}
590
591secure_vector<uint8_t> Cipher_State::hkdf_expand_label(const secure_vector<uint8_t>& secret,
592 std::string_view label,
593 const std::vector<uint8_t>& context,
594 const size_t length) const {
595 // assemble (serialized) HkdfLabel
596 secure_vector<uint8_t> hkdf_label;
597 hkdf_label.reserve(2 /* length */ + (label.size() + 6 /* 'tls13 ' */ + 1 /* length field*/) +
598 (context.size() + 1 /* length field*/));
599
600 // length
601 BOTAN_ARG_CHECK(length <= std::numeric_limits<uint16_t>::max(), "invalid length");
602 const auto len = static_cast<uint16_t>(length);
603 hkdf_label.push_back(get_byte<0>(len));
604 hkdf_label.push_back(get_byte<1>(len));
605
606 // label
607 const std::string prefix = "tls13 ";
608 BOTAN_ARG_CHECK(prefix.size() + label.size() <= 255, "label too large");
609 hkdf_label.push_back(static_cast<uint8_t>(prefix.size() + label.size()));
610 hkdf_label.insert(hkdf_label.end(), prefix.cbegin(), prefix.cend());
611 hkdf_label.insert(hkdf_label.end(), label.cbegin(), label.cend());
612
613 // context
614 BOTAN_ARG_CHECK(context.size() <= 255, "context too large");
615 hkdf_label.push_back(static_cast<uint8_t>(context.size()));
616 hkdf_label.insert(hkdf_label.end(), context.cbegin(), context.cend());
617
618 // HKDF-Expand
619 return m_expand->derive_key(
620 length, secret, hkdf_label, std::vector<uint8_t>() /* just pleasing botan's interface */);
621}
622
623secure_vector<uint8_t> Cipher_State::derive_secret(const secure_vector<uint8_t>& secret,
624 std::string_view label,
625 const Transcript_Hash& messages_hash) const {
626 return hkdf_expand_label(secret, label, messages_hash, m_hash->output_length());
627}
628
629std::vector<uint8_t> Cipher_State::empty_hash() const {
630 m_hash->update("");
631 return m_hash->final_stdvec();
632}
633
635 BOTAN_ASSERT_NOMSG(m_state == State::ServerApplicationTraffic || m_state == State::Completed);
636
637 m_read_application_traffic_secret =
638 hkdf_expand_label(m_read_application_traffic_secret, "traffic upd", {}, m_hash->output_length());
639
640 const auto secret_label = fmt("{}_TRAFFIC_SECRET_{}",
641 m_connection_side == Connection_Side::Server ? "CLIENT" : "SERVER",
642 ++m_read_key_update_count);
643 logger.maybe_log_secret(secret_label, m_read_application_traffic_secret);
644
645 derive_read_traffic_key(m_read_application_traffic_secret);
646}
647
649 BOTAN_ASSERT_NOMSG(m_state == State::ServerApplicationTraffic || m_state == State::Completed);
650 m_write_application_traffic_secret =
651 hkdf_expand_label(m_write_application_traffic_secret, "traffic upd", {}, m_hash->output_length());
652
653 const auto secret_label = fmt("{}_TRAFFIC_SECRET_{}",
654 m_connection_side == Connection_Side::Server ? "SERVER" : "CLIENT",
655 ++m_write_key_update_count);
656 logger.maybe_log_secret(secret_label, m_write_application_traffic_secret);
657
658 derive_write_traffic_key(m_write_application_traffic_secret);
659}
660
662 zap(m_read_key);
663 zap(m_read_iv);
664 zap(m_read_application_traffic_secret);
665}
666
668 zap(m_write_key);
669 zap(m_write_iv);
670 zap(m_write_application_traffic_secret);
671}
672
673} // namespace Botan::TLS
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:114
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:163
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< AEAD_Mode > create(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
Definition aead.cpp:59
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition hash.cpp:308
bool can_decrypt_application_traffic() const
static std::unique_ptr< Cipher_State > init_with_server_hello(Connection_Side side, secure_vector< uint8_t > &&shared_secret, const Ciphersuite &cipher, const Transcript_Hash &transcript_hash, const Secret_Logger &channel)
uint64_t decrypt_record_fragment(const std::vector< uint8_t > &header, secure_vector< uint8_t > &encrypted_fragment)
size_t minimum_decryption_input_length() const
bool must_expect_unprotected_alert_traffic() const
void update_write_keys(const Secret_Logger &channel)
void advance_with_client_finished(const Transcript_Hash &transcript_hash)
bool verify_peer_finished_mac(const Transcript_Hash &transcript_hash, const std::vector< uint8_t > &peer_mac) const
std::string hash_algorithm() const
static std::unique_ptr< Cipher_State > init_with_psk(Connection_Side side, PSK_Type type, secure_vector< uint8_t > &&psk, std::string_view prf_algo)
uint64_t encrypt_record_fragment(const std::vector< uint8_t > &header, secure_vector< uint8_t > &fragment)
void advance_with_client_hello(const Transcript_Hash &transcript_hash, const Secret_Logger &channel)
void advance_with_server_finished(const Transcript_Hash &transcript_hash, const Secret_Logger &channel)
void update_read_keys(const Secret_Logger &channel)
Cipher_State(const Cipher_State &other)=delete
secure_vector< uint8_t > psk(const Ticket_Nonce &nonce) const
bool is_compatible_with(const Ciphersuite &cipher) const
void advance_with_server_hello(const Ciphersuite &cipher, secure_vector< uint8_t > &&shared_secret, const Transcript_Hash &transcript_hash, const Secret_Logger &channel)
secure_vector< uint8_t > export_key(std::string_view label, std::string_view context, size_t length) const
bool can_encrypt_application_traffic() const
size_t encrypt_output_length(size_t input_length) const
std::vector< uint8_t > psk_binder_mac(const Transcript_Hash &transcript_hash_with_truncated_client_hello) const
size_t decrypt_output_length(size_t input_length) const
std::vector< uint8_t > finished_mac(const Transcript_Hash &transcript_hash) const
bool usable_in_version(Protocol_Version version) const
std::string prf_algo() const
std::string cipher_algo() const
virtual void maybe_log_secret(std::string_view label, std::span< const uint8_t > secret) const =0
constexpr T & get() &
Definition strong_type.h:85
std::vector< uint8_t > Transcript_Hash
Definition tls_magic.h:93
Strong< std::vector< uint8_t >, struct Ticket_Nonce_ > Ticket_Nonce
Used to derive the ticket's PSK from the resumption_master_secret.
Definition tls_magic.h:96
constexpr uint8_t get_byte(T input)
Definition loadstor.h:79
void zap(std::vector< T, Alloc > &vec)
Definition secmem.h:157
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
secure_vector< uint8_t > hkdf_expand_label(std::string_view hash_fn, std::span< const uint8_t > secret, std::string_view label, std::span< const uint8_t > hash_val, size_t length)
Definition hkdf.cpp:119
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 auto store_be(ParamTs &&... params)
Definition loadstor.h:745