• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 5079590438

25 May 2023 12:28PM UTC coverage: 92.228% (+0.5%) from 91.723%
5079590438

Pull #3502

github

Pull Request #3502: Apply clang-format to the codebase

75589 of 81959 relevant lines covered (92.23%)

12139530.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.19
/src/lib/tls/tls13/tls_cipher_state.cpp
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", "")
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/hkdf.h>
102
#include <botan/internal/hmac.h>
103
#include <botan/internal/loadstor.h>
104

105
namespace Botan::TLS {
106

107
namespace {
108
// RFC 8446 5.3
109
//    Each AEAD algorithm will specify a range of possible lengths for the
110
//    per-record nonce, from N_MIN bytes to N_MAX bytes of input [RFC5116].
111
//    The length of the TLS per-record nonce (iv_length) is set to the
112
//    larger of 8 bytes and N_MIN for the AEAD algorithm (see [RFC5116],
113
//    Section 4).
114
//
115
// N_MIN is 12 for AES_GCM and AES_CCM as per RFC 5116 and also 12 for ChaCha20 per RFC 8439.
116
constexpr size_t NONCE_LENGTH = 12;
117
}
118

119
std::unique_ptr<Cipher_State> Cipher_State::init_with_server_hello(const Connection_Side side,
630✔
120
                                                                   secure_vector<uint8_t>&& shared_secret,
121
                                                                   const Ciphersuite& cipher,
122
                                                                   const Transcript_Hash& transcript_hash) {
123
   auto cs = std::unique_ptr<Cipher_State>(new Cipher_State(side, cipher.prf_algo()));
630✔
124
   cs->advance_without_psk();
630✔
125
   cs->advance_with_server_hello(cipher, std::move(shared_secret), transcript_hash);
630✔
126
   return cs;
630✔
127
}
×
128

129
std::unique_ptr<Cipher_State> Cipher_State::init_with_psk(const Connection_Side side,
179✔
130
                                                          const Cipher_State::PSK_Type type,
131
                                                          secure_vector<uint8_t>&& psk,
132
                                                          const Ciphersuite& cipher) {
133
   auto cs = std::unique_ptr<Cipher_State>(new Cipher_State(side, cipher.prf_algo()));
179✔
134
   cs->advance_with_psk(type, std::move(psk));
179✔
135
   return cs;
179✔
136
}
×
137

138
void Cipher_State::advance_with_client_hello(const Transcript_Hash& transcript_hash) {
166✔
139
   BOTAN_ASSERT_NOMSG(m_state == State::PskBinder);
166✔
140

141
   zap(m_binder_key);
166✔
142

143
   // TODO: Currently 0-RTT is not yet implemented, hence we don't derive the
144
   //       early traffic secret for now.
145
   //
146
   // const auto client_early_traffic_secret = derive_secret(m_early_secret, "c e traffic", transcript_hash);
147
   // derive_write_traffic_key(client_early_traffic_secret);
148

149
   m_exporter_master_secret = derive_secret(m_early_secret, "e exp master", transcript_hash);
166✔
150

151
   m_salt = derive_secret(m_early_secret, "derived", empty_hash());
166✔
152
   zap(m_early_secret);
166✔
153

154
   m_state = State::EarlyTraffic;
166✔
155
}
166✔
156

157
void Cipher_State::advance_with_server_finished(const Transcript_Hash& transcript_hash) {
646✔
158
   BOTAN_ASSERT_NOMSG(m_state == State::HandshakeTraffic);
646✔
159

160
   const auto master_secret = hkdf_extract(secure_vector<uint8_t>(m_hash->output_length(), 0x00));
646✔
161

162
   auto client_application_traffic_secret = derive_secret(master_secret, "c ap traffic", transcript_hash);
646✔
163
   auto server_application_traffic_secret = derive_secret(master_secret, "s ap traffic", transcript_hash);
646✔
164

165
   // Note: the secrets for processing client's application data
166
   //       are not derived before the client's Finished message
167
   //       was seen and the handshake can be considered finished.
168
   if(m_connection_side == Connection_Side::Server) {
646✔
169
      derive_write_traffic_key(server_application_traffic_secret);
337✔
170
      m_read_application_traffic_secret = std::move(client_application_traffic_secret);
337✔
171
      m_write_application_traffic_secret = std::move(server_application_traffic_secret);
337✔
172
   } else {
173
      derive_read_traffic_key(server_application_traffic_secret);
309✔
174
      m_read_application_traffic_secret = std::move(server_application_traffic_secret);
309✔
175
      m_write_application_traffic_secret = std::move(client_application_traffic_secret);
309✔
176
   }
177

178
   m_exporter_master_secret = derive_secret(master_secret, "exp master", transcript_hash);
646✔
179

180
   m_state = State::ServerApplicationTraffic;
646✔
181
}
1,292✔
182

183
void Cipher_State::advance_with_client_finished(const Transcript_Hash& transcript_hash) {
584✔
184
   BOTAN_ASSERT_NOMSG(m_state == State::ServerApplicationTraffic);
584✔
185

186
   zap(m_finished_key);
584✔
187
   zap(m_peer_finished_key);
584✔
188

189
   // With the client's Finished message, the handshake is complete and
190
   // we can process client application data.
191
   if(m_connection_side == Connection_Side::Server) {
584✔
192
      derive_read_traffic_key(m_read_application_traffic_secret);
283✔
193
   } else {
194
      derive_write_traffic_key(m_write_application_traffic_secret);
301✔
195
   }
196

197
   const auto master_secret = hkdf_extract(secure_vector<uint8_t>(m_hash->output_length(), 0x00));
584✔
198

199
   m_resumption_master_secret = derive_secret(master_secret, "res master", transcript_hash);
584✔
200

201
   // This was the final state change; the salt is no longer needed.
202
   zap(m_salt);
584✔
203

204
   m_state = State::Completed;
584✔
205
}
584✔
206

207
namespace {
208

209
std::vector<uint8_t> current_nonce(const uint64_t seq_no, const secure_vector<uint8_t>& iv) {
72,034✔
210
   // RFC 8446 5.3
211
   //    The per-record nonce for the AEAD construction is formed as follows:
212
   //
213
   //    1.  The 64-bit record sequence number is encoded in network byte
214
   //        order and padded to the left with zeros to iv_length.
215
   //
216
   //    2.  The padded sequence number is XORed with either the static
217
   //        client_write_iv or server_write_iv (depending on the role).
218
   std::vector<uint8_t> nonce(NONCE_LENGTH);
72,034✔
219
   store_be(seq_no, nonce.data() + (NONCE_LENGTH - sizeof(seq_no)));
72,034✔
220
   xor_buf(nonce, iv.data(), iv.size());
72,034✔
221
   return nonce;
72,034✔
222
}
223

224
}
225

226
uint64_t Cipher_State::encrypt_record_fragment(const std::vector<uint8_t>& header, secure_vector<uint8_t>& fragment) {
2,346✔
227
   BOTAN_ASSERT_NONNULL(m_encrypt);
2,346✔
228

229
   m_encrypt->set_key(m_write_key);
2,346✔
230
   m_encrypt->set_associated_data(header);
2,346✔
231
   m_encrypt->start(current_nonce(m_write_seq_no, m_write_iv));
2,346✔
232
   m_encrypt->finish(fragment);
2,346✔
233

234
   return m_write_seq_no++;
2,346✔
235
}
236

237
uint64_t Cipher_State::decrypt_record_fragment(const std::vector<uint8_t>& header,
69,688✔
238
                                               secure_vector<uint8_t>& encrypted_fragment) {
239
   BOTAN_ASSERT_NONNULL(m_decrypt);
69,688✔
240
   BOTAN_ARG_CHECK(encrypted_fragment.size() >= m_decrypt->minimum_final_size(), "fragment too short to decrypt");
69,688✔
241

242
   m_decrypt->set_key(m_read_key);
69,688✔
243
   m_decrypt->set_associated_data(header);
69,688✔
244
   m_decrypt->start(current_nonce(m_read_seq_no, m_read_iv));
69,688✔
245

246
   m_decrypt->finish(encrypted_fragment);
69,688✔
247

248
   return m_read_seq_no++;
69,683✔
249
}
250

251
size_t Cipher_State::encrypt_output_length(const size_t input_length) const {
6,979✔
252
   BOTAN_ASSERT_NONNULL(m_encrypt);
6,979✔
253
   return m_encrypt->output_length(input_length);
6,979✔
254
}
255

256
size_t Cipher_State::decrypt_output_length(const size_t input_length) const {
69,685✔
257
   BOTAN_ASSERT_NONNULL(m_decrypt);
69,685✔
258
   return m_decrypt->output_length(input_length);
69,685✔
259
}
260

261
size_t Cipher_State::minimum_decryption_input_length() const {
69,686✔
262
   BOTAN_ASSERT_NONNULL(m_decrypt);
69,686✔
263
   return m_decrypt->minimum_final_size();
69,686✔
264
}
265

266
bool Cipher_State::must_expect_unprotected_alert_traffic() const {
20✔
267
   // Client side:
268
   //   After successfully receiving a Server Hello we expect servers to send
269
   //   alerts as protected records only, just like they start protecting their
270
   //   handshake data at this point.
271
   if(m_connection_side == Connection_Side::Client && m_state == State::EarlyTraffic) {
20✔
272
      return true;
273
   }
274

275
   // Server side:
276
   //   Servers must expect clients to send unprotected alerts during the hand-
277
   //   shake. In particular, in the response to the server's first protected
278
   //   flight. We don't expect the client to send alerts protected under the
279
   //   early traffic secret.
280
   //
281
   // TODO: when implementing PSK and/or early data for the server, we might
282
   //       need to reconsider this decision.
283
   if(m_connection_side == Connection_Side::Server &&
19✔
284
      (m_state == State::HandshakeTraffic || m_state == State::ServerApplicationTraffic)) {
9✔
285
      return true;
6✔
286
   }
287

288
   return false;
289
}
290

291
bool Cipher_State::can_encrypt_application_traffic() const {
728✔
292
   // TODO: when implementing early traffic (0-RTT) this will likely need
293
   //       to allow `State::EarlyTraffic`.
294

295
   if(m_connection_side == Connection_Side::Client && m_state != State::Completed) {
728✔
296
      return false;
297
   }
298

299
   if(m_connection_side == Connection_Side::Server && m_state != State::ServerApplicationTraffic &&
721✔
300
      m_state != State::Completed) {
301
      return false;
302
   }
303

304
   return !m_write_key.empty() && !m_write_iv.empty();
718✔
305
}
306

307
bool Cipher_State::can_decrypt_application_traffic() const {
16✔
308
   // TODO: when implementing early traffic (0-RTT) this will likely need
309
   //       to allow `State::EarlyTraffic`.
310

311
   if(m_connection_side == Connection_Side::Client && m_state != State::ServerApplicationTraffic &&
16✔
312
      m_state != State::Completed) {
313
      return false;
314
   }
315

316
   if(m_connection_side == Connection_Side::Server && m_state != State::Completed) {
14✔
317
      return false;
318
   }
319

320
   return !m_read_key.empty() && !m_read_iv.empty();
10✔
321
}
322

323
std::string Cipher_State::hash_algorithm() const {
987✔
324
   BOTAN_ASSERT_NONNULL(m_hash);
987✔
325
   return m_hash->name();
987✔
326
}
327

328
bool Cipher_State::is_compatible_with(const Ciphersuite& cipher) const {
900✔
329
   if(!cipher.usable_in_version(Protocol_Version::TLS_V13))
900✔
330
      return false;
331

332
   if(hash_algorithm() != cipher.prf_algo())
896✔
333
      return false;
334

335
   BOTAN_ASSERT_NOMSG((m_encrypt == nullptr) == (m_decrypt == nullptr));
892✔
336
   // TODO: Find a better way to check that the instantiated cipher algorithm
337
   //       is compatible with the one required by the cipher suite.
338
   // AEAD_Mode::create() sets defaults the tag length to 16 which is then
339
   // reported via AEAD_Mode::name() and hinders the trivial string comparison.
340
   if(m_encrypt && m_encrypt->name() != cipher.cipher_algo() && m_encrypt->name() != cipher.cipher_algo() + "(16)")
936✔
341
      return false;
4✔
342

343
   return true;
344
}
345

346
std::vector<uint8_t> Cipher_State::psk_binder_mac(const Transcript_Hash& transcript_hash_with_truncated_client_hello) {
188✔
347
   BOTAN_ASSERT_NOMSG(m_state == State::PskBinder);
188✔
348

349
   auto hmac = HMAC(m_hash->new_object());
188✔
350
   hmac.set_key(m_binder_key);
188✔
351
   hmac.update(transcript_hash_with_truncated_client_hello);
188✔
352
   return hmac.final_stdvec();
376✔
353
}
188✔
354

355
std::vector<uint8_t> Cipher_State::finished_mac(const Transcript_Hash& transcript_hash) const {
637✔
356
   BOTAN_ASSERT_NOMSG(m_connection_side != Connection_Side::Server || m_state == State::HandshakeTraffic);
637✔
357
   BOTAN_ASSERT_NOMSG(m_connection_side != Connection_Side::Client || m_state == State::ServerApplicationTraffic);
637✔
358
   BOTAN_ASSERT_NOMSG(!m_finished_key.empty());
637✔
359

360
   auto hmac = HMAC(m_hash->new_object());
637✔
361
   hmac.set_key(m_finished_key);
637✔
362
   hmac.update(transcript_hash);
637✔
363
   return hmac.final_stdvec();
1,274✔
364
}
637✔
365

366
bool Cipher_State::verify_peer_finished_mac(const Transcript_Hash& transcript_hash,
595✔
367
                                            const std::vector<uint8_t>& peer_mac) const {
368
   BOTAN_ASSERT_NOMSG(m_connection_side != Connection_Side::Server || m_state == State::ServerApplicationTraffic);
595✔
369
   BOTAN_ASSERT_NOMSG(m_connection_side != Connection_Side::Client || m_state == State::HandshakeTraffic);
595✔
370
   BOTAN_ASSERT_NOMSG(!m_peer_finished_key.empty());
595✔
371

372
   auto hmac = HMAC(m_hash->new_object());
595✔
373
   hmac.set_key(m_peer_finished_key);
595✔
374
   hmac.update(transcript_hash);
595✔
375
   return hmac.verify_mac(peer_mac);
1,190✔
376
}
595✔
377

378
secure_vector<uint8_t> Cipher_State::psk(const Ticket_Nonce& nonce) const {
826✔
379
   BOTAN_ASSERT_NOMSG(m_state == State::Completed);
826✔
380

381
   return derive_secret(m_resumption_master_secret, "resumption", nonce.get());
826✔
382
}
383

384
Ticket_Nonce Cipher_State::next_ticket_nonce() {
131,349✔
385
   BOTAN_STATE_CHECK(m_state == State::Completed);
131,349✔
386
   if(m_ticket_nonce == std::numeric_limits<decltype(m_ticket_nonce)>::max()) {
131,347✔
387
      throw Botan::Invalid_State("ticket nonce pool exhausted");
2✔
388
   }
389

390
   Ticket_Nonce retval(std::vector<uint8_t>(sizeof(m_ticket_nonce)));
131,345✔
391
   store_be(m_ticket_nonce++, retval.data());
131,345✔
392

393
   return retval;
131,345✔
394
}
395

396
secure_vector<uint8_t> Cipher_State::export_key(std::string_view label, std::string_view context, size_t length) const {
24✔
397
   BOTAN_ASSERT_NOMSG(can_export_keys());
24✔
398

399
   m_hash->update(context);
24✔
400
   const auto context_hash = m_hash->final_stdvec();
24✔
401
   return hkdf_expand_label(
24✔
402
      derive_secret(m_exporter_master_secret, label, empty_hash()), "exporter", context_hash, length);
72✔
403
}
24✔
404

405
namespace {
406

407
std::unique_ptr<MessageAuthenticationCode> create_hmac(std::string_view hash) {
1,618✔
408
   return std::make_unique<HMAC>(HashFunction::create_or_throw(hash));
1,618✔
409
}
410

411
}
412

413
Cipher_State::Cipher_State(Connection_Side whoami, std::string_view hash_function) :
809✔
414
      m_state(State::Uninitialized),
809✔
415
      m_connection_side(whoami),
809✔
416
      m_extract(std::make_unique<HKDF_Extract>(create_hmac(hash_function))),
809✔
417
      m_expand(std::make_unique<HKDF_Expand>(create_hmac(hash_function))),
1,618✔
418
      m_hash(HashFunction::create_or_throw(hash_function)),
809✔
419
      m_salt(m_hash->output_length(), 0x00),
809✔
420
      m_write_seq_no(0),
809✔
421
      m_read_seq_no(0),
809✔
422
      m_ticket_nonce(0) {}
1,618✔
423

424
Cipher_State::~Cipher_State() = default;
7,128✔
425

426
void Cipher_State::advance_without_psk() {
630✔
427
   BOTAN_ASSERT_NOMSG(m_state == State::Uninitialized);
630✔
428

429
   // We are not using `m_early_secret` here because the secret won't be needed
430
   // in any further state advancement methods.
431
   const auto early_secret = hkdf_extract(secure_vector<uint8_t>(m_hash->output_length(), 0x00));
630✔
432
   m_salt = derive_secret(early_secret, "derived", empty_hash());
630✔
433

434
   // Without PSK we skip the `PskBinder` state and go right to `EarlyTraffic`.
435
   m_state = State::EarlyTraffic;
630✔
436
}
630✔
437

438
void Cipher_State::advance_with_psk(PSK_Type type, secure_vector<uint8_t>&& psk) {
179✔
439
   BOTAN_ASSERT_NOMSG(m_state == State::Uninitialized);
179✔
440

441
   m_early_secret = hkdf_extract(std::move(psk));
179✔
442

443
   const char* binder_label = (type == PSK_Type::Resumption) ? "res binder" : "ext binder";
179✔
444

445
   // RFC 8446 4.2.11.2
446
   //    The PskBinderEntry is computed in the same way as the Finished message
447
   //    [...] but with the BaseKey being the binder_key derived via the key
448
   //    schedule from the corresponding PSK which is being offered.
449
   //
450
   // Hence we are doing the binder key derivation and expansion in one go.
451
   const auto binder_key = derive_secret(m_early_secret, binder_label, empty_hash());
179✔
452
   m_binder_key = hkdf_expand_label(binder_key, "finished", {}, m_hash->output_length());
179✔
453

454
   m_state = State::PskBinder;
179✔
455
}
179✔
456

457
void Cipher_State::advance_with_server_hello(const Ciphersuite& cipher,
796✔
458
                                             secure_vector<uint8_t>&& shared_secret,
459
                                             const Transcript_Hash& transcript_hash) {
460
   BOTAN_ASSERT_NOMSG(m_state == State::EarlyTraffic);
796✔
461
   BOTAN_ASSERT_NOMSG(!m_encrypt);
796✔
462
   BOTAN_ASSERT_NOMSG(!m_decrypt);
796✔
463
   BOTAN_STATE_CHECK(is_compatible_with(cipher));
796✔
464

465
   m_encrypt = AEAD_Mode::create_or_throw(cipher.cipher_algo(), Cipher_Dir::Encryption);
796✔
466
   m_decrypt = AEAD_Mode::create_or_throw(cipher.cipher_algo(), Cipher_Dir::Decryption);
796✔
467

468
   const auto handshake_secret = hkdf_extract(std::move(shared_secret));
796✔
469

470
   const auto client_handshake_traffic_secret = derive_secret(handshake_secret, "c hs traffic", transcript_hash);
796✔
471
   const auto server_handshake_traffic_secret = derive_secret(handshake_secret, "s hs traffic", transcript_hash);
796✔
472

473
   if(m_connection_side == Connection_Side::Server) {
796✔
474
      derive_read_traffic_key(client_handshake_traffic_secret, true);
358✔
475
      derive_write_traffic_key(server_handshake_traffic_secret, true);
358✔
476
   } else {
477
      derive_read_traffic_key(server_handshake_traffic_secret, true);
438✔
478
      derive_write_traffic_key(client_handshake_traffic_secret, true);
438✔
479
   }
480

481
   m_salt = derive_secret(handshake_secret, "derived", empty_hash());
796✔
482

483
   m_state = State::HandshakeTraffic;
796✔
484
}
2,388✔
485

486
void Cipher_State::derive_write_traffic_key(const secure_vector<uint8_t>& traffic_secret,
1,443✔
487
                                            const bool handshake_traffic_secret) {
488
   BOTAN_ASSERT_NONNULL(m_encrypt);
1,443✔
489

490
   m_write_key = hkdf_expand_label(traffic_secret, "key", {}, m_encrypt->minimum_keylength());
1,443✔
491
   m_write_iv = hkdf_expand_label(traffic_secret, "iv", {}, NONCE_LENGTH);
1,443✔
492
   m_write_seq_no = 0;
1,443✔
493

494
   if(handshake_traffic_secret) {
1,443✔
495
      // Key derivation for the MAC in the "Finished" handshake message as described in RFC 8446 4.4.4
496
      // (will be cleared in advance_with_server_finished())
497
      m_finished_key = hkdf_expand_label(traffic_secret, "finished", {}, m_hash->output_length());
796✔
498
   }
499
}
1,443✔
500

501
void Cipher_State::derive_read_traffic_key(const secure_vector<uint8_t>& traffic_secret,
1,417✔
502
                                           const bool handshake_traffic_secret) {
503
   BOTAN_ASSERT_NONNULL(m_encrypt);
1,417✔
504

505
   m_read_key = hkdf_expand_label(traffic_secret, "key", {}, m_encrypt->minimum_keylength());
1,417✔
506
   m_read_iv = hkdf_expand_label(traffic_secret, "iv", {}, NONCE_LENGTH);
1,417✔
507
   m_read_seq_no = 0;
1,417✔
508

509
   if(handshake_traffic_secret) {
1,417✔
510
      // Key derivation for the MAC in the "Finished" handshake message as described in RFC 8446 4.4.4
511
      // (will be cleared in advance_with_client_finished())
512
      m_peer_finished_key = hkdf_expand_label(traffic_secret, "finished", {}, m_hash->output_length());
796✔
513
   }
514
}
1,417✔
515

516
secure_vector<uint8_t> Cipher_State::hkdf_extract(secure_vector<uint8_t>&& ikm) const {
2,835✔
517
   return m_extract->derive_key(m_hash->output_length(), ikm, m_salt, std::vector<uint8_t>());
2,835✔
518
}
519

520
secure_vector<uint8_t> Cipher_State::hkdf_expand_label(const secure_vector<uint8_t>& secret,
14,454✔
521
                                                       std::string_view label,
522
                                                       const std::vector<uint8_t>& context,
523
                                                       const size_t length) const {
524
   // assemble (serialized) HkdfLabel
525
   secure_vector<uint8_t> hkdf_label;
14,454✔
526
   hkdf_label.reserve(2 /* length */ + (label.size() + 6 /* 'tls13 ' */ + 1 /* length field*/) +
14,454✔
527
                      (context.size() + 1 /* length field*/));
14,454✔
528

529
   // length
530
   BOTAN_ARG_CHECK(length <= std::numeric_limits<uint16_t>::max(), "invalid length");
14,454✔
531
   const auto len = static_cast<uint16_t>(length);
14,454✔
532
   hkdf_label.push_back(get_byte<0>(len));
14,454✔
533
   hkdf_label.push_back(get_byte<1>(len));
14,454✔
534

535
   // label
536
   const std::string prefix = "tls13 ";
14,454✔
537
   BOTAN_ARG_CHECK(prefix.size() + label.size() <= 255, "label too large");
14,454✔
538
   hkdf_label.push_back(static_cast<uint8_t>(prefix.size() + label.size()));
14,454✔
539
   hkdf_label.insert(hkdf_label.end(), prefix.cbegin(), prefix.cend());
14,454✔
540
   hkdf_label.insert(hkdf_label.end(), label.cbegin(), label.cend());
14,454✔
541

542
   // context
543
   BOTAN_ARG_CHECK(context.size() <= 255, "context too large");
14,454✔
544
   hkdf_label.push_back(static_cast<uint8_t>(context.size()));
14,454✔
545
   hkdf_label.insert(hkdf_label.end(), context.cbegin(), context.cend());
14,454✔
546

547
   // HKDF-Expand
548
   return m_expand->derive_key(
14,454✔
549
      length, secret, hkdf_label, std::vector<uint8_t>() /* just pleasing botan's interface */);
14,454✔
550
}
28,908✔
551

552
secure_vector<uint8_t> Cipher_State::derive_secret(const secure_vector<uint8_t>& secret,
6,901✔
553
                                                   std::string_view label,
554
                                                   const Transcript_Hash& messages_hash) const {
555
   return hkdf_expand_label(secret, label, messages_hash, m_hash->output_length());
6,901✔
556
}
557

558
std::vector<uint8_t> Cipher_State::empty_hash() const {
1,795✔
559
   m_hash->update("");
1,795✔
560
   return m_hash->final_stdvec();
1,795✔
561
}
562

563
void Cipher_State::update_read_keys() {
29✔
564
   BOTAN_ASSERT_NOMSG(m_state == State::ServerApplicationTraffic || m_state == State::Completed);
29✔
565

566
   m_read_application_traffic_secret =
29✔
567
      hkdf_expand_label(m_read_application_traffic_secret, "traffic upd", {}, m_hash->output_length());
29✔
568

569
   derive_read_traffic_key(m_read_application_traffic_secret);
29✔
570
}
29✔
571

572
void Cipher_State::update_write_keys() {
9✔
573
   BOTAN_ASSERT_NOMSG(m_state == State::ServerApplicationTraffic || m_state == State::Completed);
9✔
574
   m_write_application_traffic_secret =
9✔
575
      hkdf_expand_label(m_write_application_traffic_secret, "traffic upd", {}, m_hash->output_length());
9✔
576

577
   derive_write_traffic_key(m_write_application_traffic_secret);
9✔
578
}
9✔
579

580
void Cipher_State::clear_read_keys() {
534✔
581
   zap(m_read_key);
534✔
582
   zap(m_read_iv);
534✔
583
   zap(m_read_application_traffic_secret);
534✔
584
}
534✔
585

586
void Cipher_State::clear_write_keys() {
547✔
587
   zap(m_write_key);
547✔
588
   zap(m_write_iv);
547✔
589
   zap(m_write_application_traffic_secret);
547✔
590
}
547✔
591

592
}  // namespace Botan::TLS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc