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

randombit / botan / 22076829412

16 Feb 2026 08:36PM UTC coverage: 90.044%. Remained the same
22076829412

push

github

web-flow
Merge pull request #5303 from Rohde-Schwarz/refactor/tls12_13_extensions

Refactor: Organize TLS Extensions into TLS 1.2 and 1.3 Modules

102334 of 113649 relevant lines covered (90.04%)

11380212.03 hits per line

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

97.27
/src/tests/test_tls_rfc8448.cpp
1
/*
2
* (C) 2021 Jack Lloyd
3
*     2021, 2022 René Meusel, Hannes Rantzsch - neXenio GmbH
4
*     2022       René Meusel - Rohde & Schwarz Cybersecurity GmbH
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include "tests.h"
10
#include <fstream>
11
#include <memory>
12
#include <utility>
13

14
// Since RFC 8448 uses a specific set of cipher suites we can only run this
15
// test if all of them are enabled.
16
#if defined(BOTAN_HAS_TLS_12) && defined(BOTAN_HAS_TLS_13) && defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) &&             \
17
   defined(BOTAN_HAS_AEAD_GCM) && defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_X25519) && defined(BOTAN_HAS_SHA2_32) && \
18
   defined(BOTAN_HAS_SHA2_64) && defined(BOTAN_HAS_ECDSA) && defined(BOTAN_HAS_PSS)
19
   #define BOTAN_CAN_RUN_TEST_TLS_RFC8448
20
#endif
21

22
#if defined(BOTAN_CAN_RUN_TEST_TLS_RFC8448)
23
   #include "test_rng.h"
24

25
   #include <botan/assert.h>
26
   #include <botan/credentials_manager.h>
27
   #include <botan/data_src.h>
28
   #include <botan/dl_group.h>
29
   #include <botan/ec_group.h>
30
   #include <botan/hex.h>
31
   #include <botan/pk_algs.h>
32
   #include <botan/pkcs8.h>
33
   #include <botan/tls_callbacks.h>
34
   #include <botan/tls_client.h>
35
   #include <botan/tls_extensions_12.h>
36
   #include <botan/tls_extensions_13.h>
37
   #include <botan/tls_messages.h>
38
   #include <botan/tls_policy.h>
39
   #include <botan/tls_server.h>
40
   #include <botan/tls_session_manager.h>
41
   #include <botan/x509_key.h>
42
   #include <botan/internal/concat_util.h>
43
   #include <botan/internal/fmt.h>
44
   #include <botan/internal/stl_util.h>
45
#endif
46

47
namespace Botan_Tests {
48

49
#if defined(BOTAN_CAN_RUN_TEST_TLS_RFC8448)
50

51
namespace {
52

53
void add_entropy(Fixed_Output_RNG& rng, const std::vector<uint8_t>& bin) {
14✔
54
   rng.add_entropy(bin.data(), bin.size());
28✔
55
}
56

57
Botan::X509_Certificate server_certificate() {
4✔
58
   // self-signed certificate with an RSA1024 public key valid until:
59
   //   Jul 30 01:23:59 2026 GMT
60
   Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/server_certificate.pem"));
8✔
61
   return Botan::X509_Certificate(in);
4✔
62
}
4✔
63

64
Botan::X509_Certificate alternative_server_certificate() {
1✔
65
   // self-signed certificate with a P-256 public key valid until:
66
   //   Jul 30 01:24:00 2026 GMT
67
   //
68
   // This certificate is presented by the server in the "Client Authentication"
69
   // test case. Why the certificate differs in that case remains unclear.
70
   Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/server_certificate_client_auth.pem"));
2✔
71
   return Botan::X509_Certificate(in);
1✔
72
}
1✔
73

74
Botan::X509_Certificate client_certificate() {
2✔
75
   // self-signed certificate with an RSA1024 public key valid until:
76
   //   Jul 30 01:23:59 2026 GMT
77
   Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/client_certificate.pem"));
4✔
78
   return Botan::X509_Certificate(in);
2✔
79
}
2✔
80

81
std::unique_ptr<Botan::Private_Key> client_raw_public_key_pair() {
4✔
82
   // P-256 private key (independently generated)
83
   Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/client_raw_public_keypair.pem"));
8✔
84
   return Botan::PKCS8::load_key(in);
4✔
85
}
4✔
86

87
std::unique_ptr<Botan::Private_Key> server_raw_public_key_pair() {
4✔
88
   // P-256 private key (independently generated)
89
   Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/server_raw_public_keypair.pem"));
8✔
90
   return Botan::PKCS8::load_key(in);
4✔
91
}
4✔
92

93
/**
94
* Simple version of the Padding extension (RFC 7685) to reproduce the
95
* 2nd Client_Hello in RFC8448 Section 5 (HelloRetryRequest)
96
*/
97
class Padding final : public Botan::TLS::Extension {
98
   public:
99
      static Botan::TLS::Extension_Code static_type() {
100
         // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
101
         return Botan::TLS::Extension_Code(21);
102
      }
103

104
      Botan::TLS::Extension_Code type() const override { return static_type(); }
46✔
105

106
      explicit Padding(const size_t padding_bytes) : m_padding_bytes(padding_bytes) {}
2✔
107

108
      std::vector<uint8_t> serialize(Botan::TLS::Connection_Side /*whoami*/) const override {
5✔
109
         return std::vector<uint8_t>(m_padding_bytes, 0x00);
5✔
110
      }
111

112
      bool empty() const override { return m_padding_bytes == 0; }
5✔
113

114
   private:
115
      size_t m_padding_bytes;
116
};
117

118
using namespace Botan;
119
using namespace Botan::TLS;
120

121
std::chrono::system_clock::time_point from_milliseconds_since_epoch(uint64_t msecs) {
14✔
122
   const int64_t secs_since_epoch = msecs / 1000;
14✔
123
   const uint32_t additional_millis = msecs % 1000;
14✔
124

125
   BOTAN_ASSERT_NOMSG(secs_since_epoch <= std::numeric_limits<time_t>::max());
14✔
126
   return std::chrono::system_clock::from_time_t(static_cast<time_t>(secs_since_epoch)) +
14✔
127
          std::chrono::milliseconds(additional_millis);
14✔
128
}
129

130
using Modify_Exts_Fn =
131
   std::function<void(Botan::TLS::Extensions&, Botan::TLS::Connection_Side, Botan::TLS::Handshake_Type)>;
132

133
/**
134
 * We cannot actually reproduce the signatures stated in RFC 8448 as their
135
 * signature scheme is probabilistic and we're lacking the correct RNG
136
 * input. Hence, signatures are know beforehand and just reproduced by the
137
 * TLS callback when requested.
138
 */
139
struct MockSignature {
26✔
140
      std::vector<uint8_t> message_to_sign;
141
      std::vector<uint8_t> signature_to_produce;
142
};
143

144
/**
145
 * Subclass of the Botan::TLS::Callbacks instrumenting all available callbacks.
146
 * The invocation counts can be checked in the integration tests to make sure
147
 * all expected callbacks are hit. Furthermore collects the received application
148
 * data and sent record bytes for further inspection by the test cases.
149
 */
150
class Test_TLS_13_Callbacks : public Botan::TLS::Callbacks {
151
   public:
152
      Test_TLS_13_Callbacks(Modify_Exts_Fn modify_exts_cb,
14✔
153
                            std::vector<MockSignature> mock_signatures,
154
                            uint64_t timestamp) :
14✔
155
            session_activated_called(false),
14✔
156
            m_modify_exts(std::move(modify_exts_cb)),
14✔
157
            m_mock_signatures(std::move(mock_signatures)),
14✔
158
            m_timestamp(from_milliseconds_since_epoch(timestamp)) {}
14✔
159

160
      void tls_emit_data(std::span<const uint8_t> data) override {
47✔
161
         count_callback_invocation("tls_emit_data");
47✔
162
         send_buffer.insert(send_buffer.end(), data.begin(), data.end());
47✔
163
      }
47✔
164

165
      void tls_record_received(uint64_t seq_no, std::span<const uint8_t> data) override {
4✔
166
         count_callback_invocation("tls_record_received");
4✔
167
         received_seq_no = seq_no;
4✔
168
         receive_buffer.insert(receive_buffer.end(), data.begin(), data.end());
4✔
169
      }
4✔
170

171
      void tls_alert(Botan::TLS::Alert alert) override {
12✔
172
         count_callback_invocation("tls_alert");
12✔
173
         BOTAN_UNUSED(alert);
12✔
174
         // handle a tls alert received from the tls server
175
      }
12✔
176

177
      bool tls_peer_closed_connection() override {
12✔
178
         count_callback_invocation("tls_peer_closed_connection");
12✔
179
         // we want to handle the closure ourselves
180
         return false;
12✔
181
      }
182

183
      void tls_session_established(const Botan::TLS::Session_Summary& summary) override {
12✔
184
         if(const auto& psk_id = summary.external_psk_identity()) {
12✔
185
            negotiated_psk_identity = *psk_id;
2✔
186
         }
187
         count_callback_invocation("tls_session_established");
12✔
188
      }
12✔
189

190
      void tls_session_activated() override {
12✔
191
         count_callback_invocation("tls_session_activated");
12✔
192
         session_activated_called = true;
12✔
193
      }
12✔
194

195
      bool tls_should_persist_resumption_information(const Session& /*session*/) override {
2✔
196
         count_callback_invocation("tls_should_persist_resumption_information");
2✔
197
         return true;  // should always store the session
2✔
198
      }
199

200
      void tls_verify_cert_chain(const std::vector<Botan::X509_Certificate>& cert_chain,
5✔
201
                                 const std::vector<std::optional<Botan::OCSP::Response>>& /*ocsp*/,
202
                                 const std::vector<Botan::Certificate_Store*>& /*trusted*/,
203
                                 Botan::Usage_Type /*usage*/,
204
                                 std::string_view /*hostname*/,
205
                                 const Botan::TLS::Policy& /*policy*/) override {
206
         count_callback_invocation("tls_verify_cert_chain");
5✔
207
         certificate_chain = cert_chain;
5✔
208
      }
5✔
209

210
      void tls_verify_raw_public_key(const Public_Key& raw_pk,
2✔
211
                                     Usage_Type /*usage*/,
212
                                     std::string_view /*hostname*/,
213
                                     const TLS::Policy& /*policy*/) override {
214
         count_callback_invocation("tls_verify_raw_public_key");
2✔
215
         // TODO: is there a better way to copy a generic public key?
216
         raw_public_key = Botan::X509::load_key(raw_pk.subject_public_key());
2✔
217
      }
2✔
218

219
      std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const override {
×
220
         count_callback_invocation("tls_verify_cert_chain");
×
221
         return std::chrono::milliseconds(0);
×
222
      }
223

224
      std::vector<uint8_t> tls_provide_cert_status(const std::vector<X509_Certificate>& chain,
×
225
                                                   const Certificate_Status_Request& csr) override {
226
         count_callback_invocation("tls_provide_cert_status");
×
227
         return Callbacks::tls_provide_cert_status(chain, csr);
×
228
      }
229

230
      std::vector<uint8_t> tls_sign_message(const Private_Key& key,
7✔
231
                                            RandomNumberGenerator& rng,
232
                                            std::string_view padding,
233
                                            Signature_Format format,
234
                                            const std::vector<uint8_t>& msg) override {
235
         BOTAN_UNUSED(key, rng);
7✔
236
         count_callback_invocation("tls_sign_message");
7✔
237

238
         if(key.algo_name() == "RSA") {
7✔
239
            if(format != Signature_Format::Standard) {
4✔
240
               throw Test_Error("TLS implementation selected unexpected signature format for RSA");
×
241
            }
242

243
            if(padding != "PSS(SHA-256,MGF1,32)") {
8✔
244
               throw Test_Error("TLS implementation selected unexpected padding for RSA: " + std::string(padding));
×
245
            }
246
         } else if(key.algo_name() == "ECDSA") {
3✔
247
            if(format != Signature_Format::DerSequence) {
3✔
248
               throw Test_Error("TLS implementation selected unexpected signature format for ECDSA");
×
249
            }
250

251
            if(padding != "SHA-256") {
6✔
252
               throw Test_Error("TLS implementation selected unexpected padding for ECDSA: " + std::string(padding));
×
253
            }
254
         } else {
255
            throw Test_Error("TLS implementation trying to sign with unexpected algorithm (" + key.algo_name() + ")");
×
256
         }
257

258
         for(const auto& mock : m_mock_signatures) {
9✔
259
            if(mock.message_to_sign == msg) {
9✔
260
               return mock.signature_to_produce;
7✔
261
            }
262
         }
263

264
         throw Test_Error("TLS implementation produced an unexpected message to be signed: " + Botan::hex_encode(msg));
×
265
      }
×
266

267
      bool tls_verify_message(const Public_Key& key,
7✔
268
                              std::string_view padding,
269
                              Signature_Format format,
270
                              const std::vector<uint8_t>& msg,
271
                              const std::vector<uint8_t>& sig) override {
272
         count_callback_invocation("tls_verify_message");
7✔
273
         return Callbacks::tls_verify_message(key, padding, format, msg, sig);
7✔
274
      }
275

276
      std::unique_ptr<PK_Key_Agreement_Key> tls_generate_ephemeral_key(
15✔
277
         const std::variant<TLS::Group_Params, DL_Group>& group, RandomNumberGenerator& rng) override {
278
         count_callback_invocation("tls_generate_ephemeral_key");
15✔
279
         return Callbacks::tls_generate_ephemeral_key(group, rng);
15✔
280
      }
281

282
      secure_vector<uint8_t> tls_ephemeral_key_agreement(const std::variant<TLS::Group_Params, DL_Group>& group,
13✔
283
                                                         const PK_Key_Agreement_Key& private_key,
284
                                                         const std::vector<uint8_t>& public_value,
285
                                                         RandomNumberGenerator& rng,
286
                                                         const Policy& policy) override {
287
         count_callback_invocation("tls_ephemeral_key_agreement");
13✔
288
         return Callbacks::tls_ephemeral_key_agreement(group, private_key, public_value, rng, policy);
13✔
289
      }
290

291
      void tls_inspect_handshake_msg(const Handshake_Message& message) override {
102✔
292
         count_callback_invocation("tls_inspect_handshake_msg_" + message.type_string());
306✔
293

294
         try {
102✔
295
            auto serialized_message = message.serialize();
102✔
296

297
            serialized_messages.try_emplace(message.type_string())
102✔
298
               .first->second.emplace_back(std::move(serialized_message));
102✔
299
         } catch(const Not_Implemented&) {
102✔
300
            // TODO: Once the server implementation is finished, this crutch
301
            //       can likely be removed, as all message types will have a
302
            //       serialization method with actual business logic. :o)
303
         }
×
304

305
         return Callbacks::tls_inspect_handshake_msg(message);
102✔
306
      }
307

308
      std::string tls_server_choose_app_protocol(const std::vector<std::string>& client_protos) override {
×
309
         count_callback_invocation("tls_server_choose_app_protocol");
×
310
         return Callbacks::tls_server_choose_app_protocol(client_protos);
×
311
      }
312

313
      void tls_modify_extensions(Botan::TLS::Extensions& exts,
33✔
314
                                 Botan::TLS::Connection_Side side,
315
                                 Botan::TLS::Handshake_Type which_message) override {
316
         count_callback_invocation(std::string("tls_modify_extensions_") + handshake_type_to_string(which_message));
99✔
317
         m_modify_exts(exts, side, which_message);
33✔
318
         Callbacks::tls_modify_extensions(exts, side, which_message);
33✔
319
      }
33✔
320

321
      void tls_examine_extensions(const Botan::TLS::Extensions& extn,
31✔
322
                                  Connection_Side which_side,
323
                                  Botan::TLS::Handshake_Type which_message) override {
324
         count_callback_invocation(std::string("tls_examine_extensions_") + handshake_type_to_string(which_message));
93✔
325
         return Callbacks::tls_examine_extensions(extn, which_side, which_message);
31✔
326
      }
327

328
      std::string tls_peer_network_identity() override {
×
329
         count_callback_invocation("tls_peer_network_identity");
×
330
         return Callbacks::tls_peer_network_identity();
×
331
      }
332

333
      std::chrono::system_clock::time_point tls_current_timestamp() override {
23✔
334
         count_callback_invocation("tls_current_timestamp");
23✔
335
         return m_timestamp;
23✔
336
      }
337

338
      std::vector<uint8_t> pull_send_buffer() { return std::exchange(send_buffer, std::vector<uint8_t>()); }
39✔
339

340
      std::vector<uint8_t> pull_receive_buffer() { return std::exchange(receive_buffer, std::vector<uint8_t>()); }
4✔
341

342
      uint64_t last_received_seq_no() const { return received_seq_no; }
4✔
343

344
      const std::map<std::string, unsigned int>& callback_invocations() const { return m_callback_invocations; }
60✔
345

346
      void reset_callback_invocation_counters() { m_callback_invocations.clear(); }
60✔
347

348
   private:
349
      void count_callback_invocation(const std::string& callback_name) const {
339✔
350
         if(!m_callback_invocations.contains(callback_name)) {
339✔
351
            m_callback_invocations[callback_name] = 0;
320✔
352
         }
353

354
         m_callback_invocations[callback_name]++;
339✔
355
      }
339✔
356

357
   public:
358
      bool session_activated_called;                           // NOLINT(*-non-private-member-variable*)
359
      std::vector<Botan::X509_Certificate> certificate_chain;  // NOLINT(*-non-private-member-variable*)
360
      std::unique_ptr<Botan::Public_Key> raw_public_key;       // NOLINT(*-non-private-member-variable*)
361
      std::string negotiated_psk_identity;                     // NOLINT(*-non-private-member-variable*)
362
      std::map<std::string, std::vector<std::vector<uint8_t>>>
363
         serialized_messages;  // NOLINT(*-non-private-member-variable*)
364

365
   private:
366
      std::vector<uint8_t> send_buffer;
367
      std::vector<uint8_t> receive_buffer;
368
      uint64_t received_seq_no = 0;
369
      Modify_Exts_Fn m_modify_exts;
370
      std::vector<MockSignature> m_mock_signatures;
371
      std::chrono::system_clock::time_point m_timestamp;
372

373
      mutable std::map<std::string, unsigned int> m_callback_invocations;
374
};
375

376
class Test_Credentials : public Botan::Credentials_Manager {
377
   public:
378
      explicit Test_Credentials(bool use_alternative_server_certificate, std::optional<ExternalPSK> external_psk) :
14✔
379
            m_alternative_server_certificate(use_alternative_server_certificate),
14✔
380
            m_external_psk(std::move(external_psk)) {
16✔
381
         Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/server_key.pem"));
28✔
382
         m_server_private_key.reset(Botan::PKCS8::load_key(in).release());
14✔
383

384
         // RFC 8448 does not actually provide these keys. Hence we generate one on the
385
         // fly as a stand-in. Instead of actually using it, the signatures generated
386
         // by this private key must be hard-coded in `Callbacks::sign_message()`; see
387
         // `MockSignature_Fn` for more details.
388
         auto rng = Test::new_rng(__func__);
14✔
389
         m_bogus_alternative_server_private_key.reset(create_private_key("ECDSA", *rng, "secp256r1").release());
14✔
390

391
         m_client_private_key.reset(create_private_key("RSA", *rng, "1024").release());
28✔
392
      }
28✔
393

394
      std::vector<Botan::X509_Certificate> cert_chain(const std::vector<std::string>& cert_key_types,
5✔
395
                                                      const std::vector<AlgorithmIdentifier>& cert_signature_schemes,
396
                                                      const std::string& type,
397
                                                      const std::string& context) override {
398
         BOTAN_UNUSED(cert_key_types, cert_signature_schemes, context);
5✔
399
         if(type == "tls-client") {
5✔
400
            return {client_certificate()};
2✔
401
         } else if(m_alternative_server_certificate) {
4✔
402
            return {alternative_server_certificate()};
2✔
403
         } else {
404
            return {server_certificate()};
6✔
405
         }
406
      }
5✔
407

408
      std::shared_ptr<Public_Key> find_raw_public_key(const std::vector<std::string>& key_types,
2✔
409
                                                      const std::string& type,
410
                                                      const std::string& context) override {
411
         BOTAN_UNUSED(key_types, type, context);
2✔
412
         return (type == "tls-client") ? client_raw_public_key_pair()->public_key()
4✔
413
                                       : server_raw_public_key_pair()->public_key();
5✔
414
      }
415

416
      std::shared_ptr<Botan::Private_Key> private_key_for(const Botan::X509_Certificate& cert,
5✔
417
                                                          const std::string& type,
418
                                                          const std::string& context) override {
419
         BOTAN_UNUSED(cert, context);
5✔
420

421
         if(type == "tls-client") {
5✔
422
            return m_client_private_key;
1✔
423
         }
424

425
         if(m_alternative_server_certificate) {
4✔
426
            return m_bogus_alternative_server_private_key;
1✔
427
         }
428

429
         return m_server_private_key;
3✔
430
      }
431

432
      std::shared_ptr<Botan::Private_Key> private_key_for(const Public_Key& raw_public_key,
2✔
433
                                                          const std::string& type,
434
                                                          const std::string& context) override {
435
         BOTAN_UNUSED(type, context);
2✔
436
         std::vector<std::unique_ptr<Botan::Private_Key>> keys;
2✔
437
         keys.emplace_back(client_raw_public_key_pair());
2✔
438
         keys.emplace_back(server_raw_public_key_pair());
2✔
439
         for(auto& key : keys) {
3✔
440
            if(key->fingerprint_public() == raw_public_key.fingerprint_public()) {
3✔
441
               return std::move(key);
2✔
442
            }
443
         }
444
         return nullptr;
×
445
      }
2✔
446

447
      std::vector<TLS::ExternalPSK> find_preshared_keys(std::string_view /* host */,
8✔
448
                                                        TLS::Connection_Side /* whoami */,
449
                                                        const std::vector<std::string>& identities,
450
                                                        const std::optional<std::string>& prf) override {
451
         if(!m_external_psk.has_value()) {
8✔
452
            return {};
6✔
453
         }
454

455
         ExternalPSK& epsk = m_external_psk.value();
2✔
456
         const auto found = std::find(identities.begin(), identities.end(), epsk.identity());
2✔
457
         if(!identities.empty() && found == identities.end()) {
2✔
458
            return {};
×
459
         }
460

461
         if(prf && prf != epsk.prf_algo()) {
2✔
462
            return {};
×
463
         }
464

465
         // ExternalPSK has a deleted copy constructor. We need to do some gymnastics
466
         // to copy it and leave the data in m_external_psk intact
467
         const auto secret = epsk.extract_master_secret();
2✔
468
         m_external_psk = ExternalPSK(epsk.identity(), epsk.prf_algo(), secret);
2✔
469
         std::vector<ExternalPSK> psks;
2✔
470
         psks.emplace_back(epsk.identity(), epsk.prf_algo(), secret);
2✔
471
         return psks;
2✔
472
      }
4✔
473

474
   private:
475
      bool m_alternative_server_certificate;
476
      std::optional<ExternalPSK> m_external_psk;
477
      std::shared_ptr<Private_Key> m_client_private_key;
478
      std::shared_ptr<Private_Key> m_bogus_alternative_server_private_key;
479
      std::shared_ptr<Private_Key> m_server_private_key;
480
};
481

482
class RFC8448_Text_Policy : public Botan::TLS::Text_Policy {
14✔
483
   private:
484
      Botan::TLS::Text_Policy read_policy(const std::string& policy_file) {
14✔
485
         const std::string fspath = Test::data_file("tls-policy/" + policy_file + ".txt");
42✔
486

487
         std::ifstream is(fspath.c_str());
14✔
488
         if(!is.good()) {
14✔
489
            throw Test_Error("Missing policy file " + fspath);
×
490
         }
491

492
         return Botan::TLS::Text_Policy(is);
14✔
493
      }
14✔
494

495
   public:
496
      explicit RFC8448_Text_Policy(const std::string& policy_file, bool rfc8448 = true) :
14✔
497
            Botan::TLS::Text_Policy(read_policy(policy_file)), m_rfc8448(rfc8448) {}
14✔
498

499
      std::vector<Botan::TLS::Signature_Scheme> allowed_signature_schemes() const override {
16✔
500
         if(!m_rfc8448) {
16✔
501
            return Botan::TLS::Text_Policy::allowed_signature_schemes();
1✔
502
         }
503

504
         // We extend the allowed signature schemes with algorithms that we don't
505
         // actually support. The nature of the RFC 8448 test forces us to generate
506
         // bit-compatible TLS messages. Unfortunately, the test data offers all
507
         // those algorithms in its Client Hellos.
508
         return {
15✔
509
            Botan::TLS::Signature_Scheme::ECDSA_SHA256,
510
            Botan::TLS::Signature_Scheme::ECDSA_SHA384,
511
            Botan::TLS::Signature_Scheme::ECDSA_SHA512,
512
            Botan::TLS::Signature_Scheme::ECDSA_SHA1,  // not actually supported
513
            Botan::TLS::Signature_Scheme::RSA_PSS_SHA256,
514
            Botan::TLS::Signature_Scheme::RSA_PSS_SHA384,
515
            Botan::TLS::Signature_Scheme::RSA_PSS_SHA512,
516
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA256,
517
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA384,
518
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA512,
519
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA1,  // not actually supported
520
            Botan::TLS::Signature_Scheme(0x0402),          // DSA_SHA256, not actually supported
521
            Botan::TLS::Signature_Scheme(0x0502),          // DSA_SHA384, not actually supported
522
            Botan::TLS::Signature_Scheme(0x0602),          // DSA_SHA512, not actually supported
523
            Botan::TLS::Signature_Scheme(0x0202),          // DSA_SHA1, not actually supported
524
         };
15✔
525
      }
526

527
      // Overriding the key exchange group selection to favour the server's key
528
      // exchange group preference. This is required to enforce a Hello Retry Request
529
      // when testing RFC 8448 5. from the server side.
530
      Named_Group choose_key_exchange_group(const std::vector<Group_Params>& supported_by_peer,
8✔
531
                                            const std::vector<Group_Params>& offered_by_peer) const override {
532
         BOTAN_UNUSED(offered_by_peer);
8✔
533

534
         const auto supported_by_us = key_exchange_groups();
8✔
535
         const auto selected_group =
8✔
536
            std::find_if(supported_by_us.begin(), supported_by_us.end(), [&](const auto group) {
8✔
537
               return value_exists(supported_by_peer, group);
16✔
538
            });
539

540
         return selected_group != supported_by_us.end() ? *selected_group : Named_Group::NONE;
8✔
541
      }
8✔
542

543
   private:
544
      bool m_rfc8448;
545
};
546

547
/**
548
 * In-Memory Session Manager that stores sessions verbatim, without encryption.
549
 * Therefor it is not dependent on a random number generator and can easily be
550
 * instrumented for test inspection.
551
 */
552
class RFC8448_Session_Manager : public Botan::TLS::Session_Manager {
553
   private:
554
      decltype(auto) find_by_handle(const Session_Handle& handle) {
3✔
555
         return [=](const Session_with_Handle& session) {
18✔
556
            if(session.handle.id().has_value() && handle.id().has_value() &&
4✔
557
               session.handle.id().value() == handle.id().value()) {
2✔
558
               return true;
559
            }
560
            if(session.handle.ticket().has_value() && handle.ticket().has_value() &&
10✔
561
               session.handle.ticket().value() == handle.ticket().value()) {
10✔
562
               return true;
563
            }
564
            return false;
565
         };
6✔
566
      }
567

568
   public:
569
      RFC8448_Session_Manager() : Session_Manager(std::make_shared<Botan::Null_RNG>()) {}
28✔
570

571
      const std::vector<Session_with_Handle>& all_sessions() const { return m_sessions; }
3✔
572

573
      void store(const Session& session, const Session_Handle& handle) override {
4✔
574
         m_sessions.push_back({session, handle});
4✔
575
      }
12✔
576

577
      std::optional<Session_Handle> establish(const Session& session,
1✔
578
                                              const std::optional<Session_ID>& /*session*/,
579
                                              bool /*no_ticket*/) override {
580
         // we assume that the 'mocked' session is already stored in the manager,
581
         // verify that it is equivalent to the one created by the testee and
582
         // return the associated handle stored with it
583

584
         if(m_sessions.size() != 1) {
1✔
585
            throw Test_Error("No mocked session handle available; Test bug?");
×
586
         }
587

588
         const auto& [mocked_session, handle] = m_sessions.front();
1✔
589
         if(mocked_session.master_secret() != session.master_secret()) {
1✔
590
            throw Test_Error("Generated session object does not match the expected mock");
×
591
         }
592

593
         return handle;
1✔
594
      }
595

596
      std::optional<Session> retrieve_one(const Session_Handle& handle) override {
2✔
597
         auto itr = std::find_if(m_sessions.begin(), m_sessions.end(), find_by_handle(handle));
2✔
598
         if(itr == m_sessions.end()) {
2✔
599
            return std::nullopt;
1✔
600
         } else {
601
            return itr->session;
1✔
602
         }
603
      }
604

605
      std::vector<Session_with_Handle> find_some(const Server_Information& info,
7✔
606
                                                 const size_t /*max_sessions_hint*/) override {
607
         std::vector<Session_with_Handle> found_sessions;
7✔
608
         for(const auto& [session, handle] : m_sessions) {
8✔
609
            if(session.server_info() == info) {
1✔
610
               found_sessions.emplace_back(Session_with_Handle{session, handle});
2✔
611
            }
612
         }
613

614
         return found_sessions;
7✔
615
      }
×
616

617
      size_t remove(const Session_Handle& handle) override { return std::erase_if(m_sessions, find_by_handle(handle)); }
2✔
618

619
      size_t remove_all() override {
×
620
         const auto sessions = m_sessions.size();
×
621
         m_sessions.clear();
×
622
         return sessions;
×
623
      }
624

625
   private:
626
      std::vector<Session_with_Handle> m_sessions;
627
};
628

629
/**
630
 * This steers the TLS client handle and is the central entry point for the
631
 * test cases to interact with the TLS 1.3 implementation.
632
 *
633
 * Note: This class is abstract to be subclassed for both client and server tests.
634
 */
635
class TLS_Context {
636
   protected:
637
      TLS_Context(std::shared_ptr<Botan::RandomNumberGenerator> rng_in,
14✔
638
                  std::shared_ptr<const RFC8448_Text_Policy> policy,
639
                  Modify_Exts_Fn modify_exts_cb,
640
                  std::vector<MockSignature> mock_signatures,
641
                  uint64_t timestamp,
642
                  std::optional<std::pair<Session, Session_Ticket>> session_and_ticket,
643
                  std::optional<ExternalPSK> external_psk,
644
                  bool use_alternative_server_certificate) :
14✔
645
            m_callbacks(std::make_shared<Test_TLS_13_Callbacks>(
14✔
646
               std::move(modify_exts_cb), std::move(mock_signatures), timestamp)),
647
            m_creds(std::make_shared<Test_Credentials>(use_alternative_server_certificate, std::move(external_psk))),
14✔
648
            m_rng(std::move(rng_in)),
14✔
649
            m_session_mgr(std::make_shared<RFC8448_Session_Manager>()),
650
            m_policy(std::move(policy)) {
28✔
651
         if(session_and_ticket.has_value()) {
14✔
652
            m_session_mgr->store(std::get<Session>(session_and_ticket.value()),
6✔
653
                                 Botan::TLS::Session_Handle(std::get<Session_Ticket>(session_and_ticket.value())));
9✔
654
         }
655
      }
14✔
656

657
   public:
658
      virtual ~TLS_Context() = default;
70✔
659

660
      TLS_Context(TLS_Context&) = delete;
661
      TLS_Context& operator=(const TLS_Context&) = delete;
662

663
      TLS_Context(TLS_Context&&) = delete;
664
      TLS_Context& operator=(TLS_Context&&) = delete;
665

666
      std::vector<uint8_t> pull_send_buffer() { return m_callbacks->pull_send_buffer(); }
39✔
667

668
      std::vector<uint8_t> pull_receive_buffer() { return m_callbacks->pull_receive_buffer(); }
4✔
669

670
      uint64_t last_received_seq_no() const { return m_callbacks->last_received_seq_no(); }
4✔
671

672
      /**
673
       * Checks that all of the listed callbacks were called at least once, no other
674
       * callbacks were called in addition to the expected ones. After the checks are
675
       * done, the callback invocation counters are reset.
676
       */
677
      void check_callback_invocations(Test::Result& result,
60✔
678
                                      const std::string& context,
679
                                      const std::vector<std::string>& callback_names) {
680
         const auto& invokes = m_callbacks->callback_invocations();
60✔
681
         for(const auto& cbn : callback_names) {
371✔
682
            result.test_is_true(Botan::fmt("{} was invoked (Context: {})", cbn, context),
933✔
683
                                invokes.contains(cbn) && invokes.at(cbn) > 0);
311✔
684
         }
685

686
         for(const auto& invoke : invokes) {
371✔
687
            if(invoke.second == 0) {
311✔
688
               continue;
×
689
            }
690
            result.test_is_true(
622✔
691
               invoke.first + " was expected (Context: " + context + ")",
1,244✔
692
               std::find(callback_names.cbegin(), callback_names.cend(), invoke.first) != callback_names.cend());
622✔
693
         }
694

695
         m_callbacks->reset_callback_invocation_counters();
60✔
696
      }
60✔
697

698
      const std::vector<Session_with_Handle>& stored_sessions() const { return m_session_mgr->all_sessions(); }
3✔
699

700
      const std::vector<Botan::X509_Certificate>& certs_verified() const { return m_callbacks->certificate_chain; }
2✔
701

702
      const std::string& psk_identity_negotiated() const { return m_callbacks->negotiated_psk_identity; }
2✔
703

704
      decltype(auto) observed_handshake_messages() const { return m_callbacks->serialized_messages; }
7✔
705

706
      /**
707
       * Send application data through the secure channel
708
       */
709
      virtual void send(const std::vector<uint8_t>& data) = 0;
710

711
   protected:
712
      std::shared_ptr<Test_TLS_13_Callbacks> m_callbacks;  // NOLINT(*-non-private-member-variable*)
713
      std::shared_ptr<Test_Credentials> m_creds;           // NOLINT(*-non-private-member-variable*)
714

715
      std::shared_ptr<Botan::RandomNumberGenerator> m_rng;     // NOLINT(*-non-private-member-variable*)
716
      std::shared_ptr<RFC8448_Session_Manager> m_session_mgr;  // NOLINT(*-non-private-member-variable*)
717
      std::shared_ptr<const RFC8448_Text_Policy> m_policy;     // NOLINT(*-non-private-member-variable*)
718
};
719

720
class Client_Context : public TLS_Context {
721
   public:
722
      Client_Context(std::shared_ptr<Botan::RandomNumberGenerator> rng_in,
7✔
723
                     std::shared_ptr<const RFC8448_Text_Policy> policy,
724
                     uint64_t timestamp,
725
                     Modify_Exts_Fn modify_exts_cb,
726
                     std::optional<std::pair<Session, Session_Ticket>> session_and_ticket = std::nullopt,
727
                     std::optional<ExternalPSK> external_psk = std::nullopt,
728
                     std::vector<MockSignature> mock_signatures = {}) :
7✔
729
            TLS_Context(std::move(rng_in),
730
                        std::move(policy),
731
                        std::move(modify_exts_cb),
732
                        std::move(mock_signatures),
733
                        timestamp,
734
                        std::move(session_and_ticket),
735
                        std::move(external_psk),
736
                        false),
737
            client(m_callbacks,
35✔
738
                   m_session_mgr,
7✔
739
                   m_creds,
7✔
740
                   m_policy,
7✔
741
                   m_rng,
7✔
742
                   Botan::TLS::Server_Information("server"),
14✔
743
                   Botan::TLS::Protocol_Version::TLS_V13) {}
30✔
744

745
      void send(const std::vector<uint8_t>& data) override { client.send(data.data(), data.size()); }
2✔
746

747
      Botan::TLS::Client client;  // NOLINT(*-non-private-member-variable*)
748
};
749

750
class Server_Context : public TLS_Context {
751
   public:
752
      Server_Context(std::shared_ptr<Botan::RandomNumberGenerator> rng,
7✔
753
                     std::shared_ptr<const RFC8448_Text_Policy> policy,
754
                     uint64_t timestamp,
755
                     Modify_Exts_Fn modify_exts_cb,
756
                     std::vector<MockSignature> mock_signatures,
757
                     bool use_alternative_server_certificate = false,
758
                     std::optional<std::pair<Session, Session_Ticket>> session_and_ticket = std::nullopt,
759
                     std::optional<ExternalPSK> external_psk = std::nullopt) :
7✔
760
            TLS_Context(std::move(rng),
761
                        std::move(policy),
762
                        std::move(modify_exts_cb),
763
                        std::move(mock_signatures),
764
                        timestamp,
765
                        std::move(session_and_ticket),
766
                        std::move(external_psk),
767
                        use_alternative_server_certificate),
768
            server(m_callbacks, m_session_mgr, m_creds, m_policy, m_rng, false /* DTLS NYI */) {}
51✔
769

770
      void send(const std::vector<uint8_t>& data) override { server.send(data.data(), data.size()); }
2✔
771

772
      Botan::TLS::Server server;  // NOLINT(*-non-private-member-variable*)
773
};
774

775
void sort_extensions(Botan::TLS::Extensions& exts, const std::vector<Botan::TLS::Extension_Code>& expected_order) {
30✔
776
   for(const auto ext_type : expected_order) {
283✔
777
      auto ext = exts.take(ext_type);
253✔
778
      if(ext != nullptr) {
253✔
779
         exts.add(std::move(ext));
230✔
780
      }
781
   }
253✔
782
}
30✔
783

784
/**
785
 * Because of the nature of the RFC 8448 test data we need to produce bit-compatible
786
 * TLS messages. Hence we sort the generated TLS extensions exactly as expected.
787
 */
788
void sort_rfc8448_extensions(Botan::TLS::Extensions& exts,
23✔
789
                             Botan::TLS::Connection_Side side,
790
                             Botan::TLS::Handshake_Type /*type*/ = Botan::TLS::Handshake_Type::ClientHello) {
791
   if(side == Botan::TLS::Connection_Side::Client) {
23✔
792
      sort_extensions(exts,
12✔
793
                      {
794
                         Botan::TLS::Extension_Code::ServerNameIndication,
795
                         Botan::TLS::Extension_Code::SafeRenegotiation,
796
                         Botan::TLS::Extension_Code::SupportedGroups,
797
                         Botan::TLS::Extension_Code::SessionTicket,
798
                         Botan::TLS::Extension_Code::KeyShare,
799
                         Botan::TLS::Extension_Code::EarlyData,
800
                         Botan::TLS::Extension_Code::SupportedVersions,
801
                         Botan::TLS::Extension_Code::SignatureAlgorithms,
802
                         Botan::TLS::Extension_Code::Cookie,
803
                         Botan::TLS::Extension_Code::PskKeyExchangeModes,
804
                         Botan::TLS::Extension_Code::RecordSizeLimit,
805
                         Padding::static_type(),
806
                         Botan::TLS::Extension_Code::PresharedKey,
807
                      });
808
   } else {
809
      sort_extensions(exts,
34✔
810
                      {
811
                         Botan::TLS::Extension_Code::SupportedGroups,
812
                         Botan::TLS::Extension_Code::KeyShare,
813
                         Botan::TLS::Extension_Code::Cookie,
814
                         Botan::TLS::Extension_Code::SupportedVersions,
815
                         Botan::TLS::Extension_Code::SignatureAlgorithms,
816
                         Botan::TLS::Extension_Code::RecordSizeLimit,
817
                         Botan::TLS::Extension_Code::ServerNameIndication,
818
                         Botan::TLS::Extension_Code::EarlyData,
819
                      });
820
   }
821
}
23✔
822

823
void add_renegotiation_extension(Botan::TLS::Extensions& exts) {
5✔
824
   // Renegotiation is not possible in TLS 1.3. Nevertheless, RFC 8448 requires
825
   // to add this to the Client Hello for reasons.
826
   exts.add(new Renegotiation_Extension());  // NOLINT(*-owning-memory)
5✔
827
}
5✔
828

829
void add_early_data_indication(Botan::TLS::Extensions& exts) {
1✔
830
   exts.add(new Botan::TLS::EarlyDataIndication());  // NOLINT(*-owning-memory)
1✔
831
}
1✔
832

833
std::vector<uint8_t> strip_message_header(const std::vector<uint8_t>& msg) {
31✔
834
   BOTAN_ASSERT_NOMSG(msg.size() >= 4);
31✔
835
   return {msg.begin() + 4, msg.end()};
31✔
836
}
837

838
std::vector<MockSignature> make_mock_signatures(const VarMap& vars) {
9✔
839
   std::vector<MockSignature> result;
9✔
840

841
   auto mock = [&](const std::string& msg, const std::string& sig) {
27✔
842
      if(vars.has_key(msg) && vars.has_key(sig)) {
18✔
843
         result.push_back({vars.get_opt_bin(msg), vars.get_opt_bin(sig)});
22✔
844
      }
845
   };
29✔
846

847
   mock("Server_MessageToSign", "Server_MessageSignature");
18✔
848
   mock("Client_MessageToSign", "Client_MessageSignature");
18✔
849

850
   return result;
9✔
851
}
×
852

853
}  // namespace
854

855
/**
856
 * Traffic transcripts and supporting data for the TLS RFC 8448 and TLS policy
857
 * configuration is kept in data files (accessible via `Test:::data_file()`).
858
 *
859
 * tls_13_rfc8448/transcripts.vec
860
 *   The record transcripts and RNG outputs as defined/required in RFC 8448 in
861
 *   Botan's Text_Based_Test vector format. Data from each RFC 8448 section is
862
 *   placed in a sub-section of the *.vec file. Each of those sections needs a
863
 *   specific test case implementation that is dispatched in `run_one_test()`.
864
 *
865
 * tls_13_rfc8448/client_certificate.pem
866
 *   The client certificate provided in RFC 8448 used to perform client auth.
867
 *   Note that RFC 8448 _does not_ provide the associated private key but only
868
 *   the resulting signature in the client's CertificateVerify message.
869
 *
870
 * tls_13_rfc8448/server_certificate.pem
871
 * tls_13_rfc8448/server_key.pem
872
 *   The server certificate and its associated private key.
873
 *
874
 * tls_13_rfc8448/server_certificate_client_auth.pem
875
 *   The server certificate used in the Client Authentication test case.
876
 *
877
 * tls_13_rfc8448/client_raw_public_keypair.pem
878
 * tls_13_rfc8448/server_raw_public_keypair.pem
879
 *   The raw public key pairs for client and server authentication in the
880
 *   equally named test cases.
881
 *
882
 * tls-policy/rfc8448_*.txt
883
 *   Each RFC 8448 section test required a slightly adapted Botan TLS policy
884
 *   to enable/disable certain features under test.
885
 *
886
 * While the test cases are split into Client-side and Server-side tests, the
887
 * transcript data is reused. See the concrete implementations of the abstract
888
 * Test_TLS_RFC8448 test class.
889
 */
890
class Test_TLS_RFC8448 : public Text_Based_Test {
891
   protected:
892
      // Those tests are based on the test vectors in RFC8448.
893
      virtual std::vector<Test::Result> simple_1_rtt(const VarMap& vars) = 0;
894
      virtual std::vector<Test::Result> resumed_handshake_with_0_rtt(const VarMap& vars) = 0;
895
      virtual std::vector<Test::Result> hello_retry_request(const VarMap& vars) = 0;
896
      virtual std::vector<Test::Result> client_authentication(const VarMap& vars) = 0;
897
      virtual std::vector<Test::Result> middlebox_compatibility(const VarMap& vars) = 0;
898

899
      // Those tests provide the same information as RFC8448 test vectors but
900
      // were sourced otherwise. Typically by temporarily instrumenting our implementation.
901
      virtual std::vector<Test::Result> externally_provided_psk_with_ephemeral_key(const VarMap& vars) = 0;
902
      virtual std::vector<Test::Result> raw_public_key_with_client_authentication(const VarMap& vars) = 0;
903

904
      virtual std::string side() const = 0;
905

906
   public:
907
      Test_TLS_RFC8448() :
2✔
908
            Text_Based_Test("tls_13_rfc8448/transcripts.vec",
909
                            // mandatory data fields
910
                            "Client_RNG_Pool,"
911
                            "Server_RNG_Pool,"
912
                            "CurrentTimestamp,"
913
                            "Record_ClientHello_1,"
914
                            "Record_ServerHello,"
915
                            "Record_ServerHandshakeMessages,"
916
                            "Record_ClientFinished,"
917
                            "Record_Client_CloseNotify,"
918
                            "Record_Server_CloseNotify",
919
                            // optional data fields
920
                            "Message_ServerHello,"
921
                            "Message_EncryptedExtensions,"
922
                            "Message_CertificateRequest,"
923
                            "Message_Server_Certificate,"
924
                            "Message_Server_CertificateVerify,"
925
                            "Message_Server_Finished,"
926
                            "Record_HelloRetryRequest,"
927
                            "Record_ClientHello_2,"
928
                            "Record_NewSessionTicket,"
929
                            "Client_AppData,"
930
                            "Record_Client_AppData,"
931
                            "Server_AppData,"
932
                            "Record_Server_AppData,"
933
                            "Client_EarlyAppData,"
934
                            "Record_Client_EarlyAppData,"
935
                            "SessionTicket,"
936
                            "Client_SessionData,"
937
                            "Server_MessageToSign,"
938
                            "Server_MessageSignature,"
939
                            "Client_MessageToSign,"
940
                            "Client_MessageSignature,"
941
                            "HelloRetryRequest_Cookie,"
942
                            "PskIdentity,"
943
                            "PskPRF,"
944
                            "PskSecret") {}
4✔
945

946
      Test::Result run_one_test(const std::string& header, const VarMap& vars) override {
14✔
947
         if(header == "Simple_1RTT_Handshake") {
14✔
948
            return Test::Result("Simple 1-RTT (" + side() + " side)", simple_1_rtt(vars));
8✔
949
         } else if(header == "Resumed_0RTT_Handshake") {
12✔
950
            return Test::Result("Resumption with 0-RTT data (" + side() + " side)", resumed_handshake_with_0_rtt(vars));
8✔
951
         } else if(header == "HelloRetryRequest_Handshake") {
10✔
952
            return Test::Result("Handshake involving Hello Retry Request (" + side() + " side)",
8✔
953
                                hello_retry_request(vars));
6✔
954
         } else if(header == "Client_Authentication_Handshake") {
8✔
955
            return Test::Result("Client Authentication (" + side() + " side)", client_authentication(vars));
8✔
956
         } else if(header == "Middlebox_Compatibility_Mode") {
6✔
957
            return Test::Result("Middlebox Compatibility Mode (" + side() + " side)", middlebox_compatibility(vars));
8✔
958
         } else if(header == "Externally_Provided_PSK_with_Ephemeral_Key") {
4✔
959
            return Test::Result("Externally Provided PSK with ephemeral key (" + side() + " side)",
8✔
960
                                externally_provided_psk_with_ephemeral_key(vars));
6✔
961
         } else if(header == "RawPublicKey_With_Client_Authentication") {
2✔
962
            return Test::Result("RawPublicKey with Client Authentication (" + side() + " side)",
8✔
963
                                raw_public_key_with_client_authentication(vars));
6✔
964
         } else {
965
            return Test::Result::Failure("test dispatcher", "unknown sub-test: " + header);
×
966
         }
967
      }
968
};
969

970
class Test_TLS_RFC8448_Client : public Test_TLS_RFC8448 {
1✔
971
   private:
972
      std::string side() const override { return "Client"; }
7✔
973

974
      std::vector<Test::Result> simple_1_rtt(const VarMap& vars) override {
1✔
975
         auto rng = std::make_shared<Fixed_Output_RNG>("");
1✔
976

977
         // 32 - for client hello random
978
         // 32 - for KeyShare (eph. x25519 key pair)
979
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
1✔
980

981
         auto add_extensions_and_sort = [](Botan::TLS::Extensions& exts,
2✔
982
                                           Botan::TLS::Connection_Side side,
983
                                           Botan::TLS::Handshake_Type which_message) {
984
            if(which_message == Handshake_Type::ClientHello) {
1✔
985
               // For some reason, presumably checking compatibility, the RFC 8448 Client
986
               // Hello includes a (TLS 1.2) Session_Ticket extension. We don't normally add
987
               // this obsoleted extension in a TLS 1.3 client.
988
               exts.add(new Botan::TLS::Session_Ticket_Extension());  // NOLINT(*-owning-memory)
1✔
989

990
               add_renegotiation_extension(exts);
1✔
991
               sort_rfc8448_extensions(exts, side);
1✔
992
            }
993
         };
1✔
994

995
         std::unique_ptr<Client_Context> ctx;
1✔
996

997
         return {
1✔
998
            CHECK("Client Hello",
999
                  [&](Test::Result& result) {
1✔
1000
                     ctx = std::make_unique<Client_Context>(rng,
1✔
1001
                                                            std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
2✔
1002
                                                            vars.get_req_u64("CurrentTimestamp"),
1✔
1003
                                                            add_extensions_and_sort);
1✔
1004

1005
                     result.test_is_true("client not closed", !ctx->client.is_closed());
1✔
1006
                     ctx->check_callback_invocations(result,
2✔
1007
                                                     "client hello prepared",
1008
                                                     {
1009
                                                        "tls_emit_data",
1010
                                                        "tls_inspect_handshake_msg_client_hello",
1011
                                                        "tls_modify_extensions_client_hello",
1012
                                                        "tls_generate_ephemeral_key",
1013
                                                        "tls_current_timestamp",
1014
                                                     });
1015

1016
                     result.test_bin_eq(
1✔
1017
                        "TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
1✔
1018
                  }),
1✔
1019

1020
            CHECK("Server Hello",
1021
                  [&](Test::Result& result) {
1✔
1022
                     result.require("ctx is available", ctx != nullptr);
1✔
1023
                     const auto server_hello = vars.get_req_bin("Record_ServerHello");
1✔
1024
                     // splitting the input data to test partial reads
1025
                     const std::vector<uint8_t> server_hello_a(server_hello.begin(), server_hello.begin() + 20);
1✔
1026
                     const std::vector<uint8_t> server_hello_b(server_hello.begin() + 20, server_hello.end());
1✔
1027

1028
                     ctx->client.received_data(server_hello_a);
1✔
1029
                     ctx->check_callback_invocations(result, "server hello partially received", {});
2✔
1030

1031
                     ctx->client.received_data(server_hello_b);
1✔
1032
                     ctx->check_callback_invocations(result,
2✔
1033
                                                     "server hello received",
1034
                                                     {"tls_inspect_handshake_msg_server_hello",
1035
                                                      "tls_examine_extensions_server_hello",
1036
                                                      "tls_ephemeral_key_agreement"});
1037

1038
                     result.test_is_true("client is not yet active", !ctx->client.is_active());
1✔
1039
                     result.test_is_true("handshake is not yet complete", !ctx->client.is_handshake_complete());
1✔
1040
                  }),
1✔
1041

1042
            CHECK("Server HS messages .. Client Finished",
1043
                  [&](Test::Result& result) {
1✔
1044
                     result.require("ctx is available", ctx != nullptr);
1✔
1045
                     ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
1✔
1046

1047
                     ctx->check_callback_invocations(result,
2✔
1048
                                                     "encrypted handshake messages received",
1049
                                                     {"tls_inspect_handshake_msg_encrypted_extensions",
1050
                                                      "tls_inspect_handshake_msg_certificate",
1051
                                                      "tls_inspect_handshake_msg_certificate_verify",
1052
                                                      "tls_inspect_handshake_msg_finished",
1053
                                                      "tls_examine_extensions_encrypted_extensions",
1054
                                                      "tls_examine_extensions_certificate",
1055
                                                      "tls_emit_data",
1056
                                                      "tls_current_timestamp",
1057
                                                      "tls_session_established",
1058
                                                      "tls_session_activated",
1059
                                                      "tls_verify_cert_chain",
1060
                                                      "tls_verify_message"});
1061
                     result.require("certificate exists", !ctx->certs_verified().empty());
1✔
1062
                     result.require("correct certificate", ctx->certs_verified().front() == server_certificate());
1✔
1063
                     result.require("client is active", ctx->client.is_active());
1✔
1064
                     result.test_is_true("handshake is complete", ctx->client.is_handshake_complete());
1✔
1065

1066
                     result.test_bin_eq("correct handshake finished",
1✔
1067
                                        ctx->pull_send_buffer(),
1✔
1068
                                        vars.get_req_bin("Record_ClientFinished"));
2✔
1069
                  }),
1✔
1070

1071
            CHECK("Post-Handshake: NewSessionTicket",
1072
                  [&](Test::Result& result) {
1✔
1073
                     result.require("ctx is available", ctx != nullptr);
1✔
1074
                     result.require("no sessions so far", ctx->stored_sessions().empty());
1✔
1075
                     ctx->client.received_data(vars.get_req_bin("Record_NewSessionTicket"));
1✔
1076

1077
                     ctx->check_callback_invocations(result,
2✔
1078
                                                     "new session ticket received",
1079
                                                     {"tls_examine_extensions_new_session_ticket",
1080
                                                      "tls_should_persist_resumption_information",
1081
                                                      "tls_current_timestamp"});
1082
                     if(result.test_sz_eq("session was stored", ctx->stored_sessions().size(), 1)) {
1✔
1083
                        const auto& [stored_session, stored_handle] = ctx->stored_sessions().front();
1✔
1084
                        result.require("session handle contains a ticket", stored_handle.ticket().has_value());
1✔
1085
                        result.test_bin_eq("session was serialized as expected",
1✔
1086
                                           stored_session.DER_encode(),
1✔
1087
                                           vars.get_req_bin("Client_SessionData"));
2✔
1088
                     }
1089
                  }),
1✔
1090

1091
            CHECK("Send Application Data",
1092
                  [&](Test::Result& result) {
1✔
1093
                     result.require("ctx is available", ctx != nullptr);
1✔
1094
                     ctx->send(vars.get_req_bin("Client_AppData"));
2✔
1095

1096
                     ctx->check_callback_invocations(result, "application data sent", {"tls_emit_data"});
2✔
1097

1098
                     result.test_bin_eq("correct client application data",
1✔
1099
                                        ctx->pull_send_buffer(),
1✔
1100
                                        vars.get_req_bin("Record_Client_AppData"));
2✔
1101
                  }),
1✔
1102

1103
            CHECK("Receive Application Data",
1104
                  [&](Test::Result& result) {
1✔
1105
                     result.require("ctx is available", ctx != nullptr);
1✔
1106
                     ctx->client.received_data(vars.get_req_bin("Record_Server_AppData"));
1✔
1107

1108
                     ctx->check_callback_invocations(result, "application data sent", {"tls_record_received"});
2✔
1109

1110
                     const auto rcvd = ctx->pull_receive_buffer();
1✔
1111
                     result.test_bin_eq("decrypted application traffic", rcvd, vars.get_req_bin("Server_AppData"));
1✔
1112
                     result.test_u64_eq("sequence number", ctx->last_received_seq_no(), uint64_t(1));
1✔
1113
                  }),
1✔
1114

1115
            CHECK("Close Connection",
1116
                  [&](Test::Result& result) {
1✔
1117
                     result.require("ctx is available", ctx != nullptr);
1✔
1118
                     ctx->client.close();
1✔
1119

1120
                     result.test_bin_eq(
1✔
1121
                        "close payload", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
1✔
1122
                     ctx->check_callback_invocations(result, "CLOSE_NOTIFY sent", {"tls_emit_data"});
2✔
1123

1124
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
1✔
1125
                     ctx->check_callback_invocations(
2✔
1126
                        result, "CLOSE_NOTIFY received", {"tls_alert", "tls_peer_closed_connection"});
1127

1128
                     result.test_is_true("connection is closed", ctx->client.is_closed());
1✔
1129
                  }),
1✔
1130
         };
8✔
1131
      }
3✔
1132

1133
      std::vector<Test::Result> resumed_handshake_with_0_rtt(const VarMap& vars) override {
1✔
1134
         auto rng = std::make_unique<Fixed_Output_RNG>("");
1✔
1135

1136
         // 32 - for client hello random
1137
         // 32 - for KeyShare (eph. x25519 key pair)
1138
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
1✔
1139

1140
         auto add_extensions_and_sort = [](Botan::TLS::Extensions& exts,
2✔
1141
                                           Botan::TLS::Connection_Side side,
1142
                                           Botan::TLS::Handshake_Type which_message) {
1143
            if(which_message == Handshake_Type::ClientHello) {
1✔
1144
               exts.add(new Padding(87));  // NOLINT(*-owning-memory)
1✔
1145

1146
               add_renegotiation_extension(exts);
1✔
1147

1148
               // TODO: Implement early data support and remove this 'hack'.
1149
               //
1150
               // Currently, the production implementation will never add this
1151
               // extension even if the resumed session would allow early data.
1152
               add_early_data_indication(exts);
1✔
1153
               sort_rfc8448_extensions(exts, side);
1✔
1154
            }
1155
         };
1✔
1156

1157
         std::unique_ptr<Client_Context> ctx;
1✔
1158

1159
         return {
1✔
1160
            CHECK("Client Hello",
1161
                  [&](Test::Result& result) {
1✔
1162
                     ctx = std::make_unique<Client_Context>(
1✔
1163
                        std::move(rng),
1164
                        std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
2✔
1165
                        vars.get_req_u64("CurrentTimestamp"),
2✔
1166
                        add_extensions_and_sort,
1167
                        std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
4✔
1168
                                  Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1169

1170
                     result.test_is_true("client not closed", !ctx->client.is_closed());
1✔
1171
                     ctx->check_callback_invocations(result,
2✔
1172
                                                     "client hello prepared",
1173
                                                     {
1174
                                                        "tls_emit_data",
1175
                                                        "tls_inspect_handshake_msg_client_hello",
1176
                                                        "tls_modify_extensions_client_hello",
1177
                                                        "tls_current_timestamp",
1178
                                                        "tls_generate_ephemeral_key",
1179
                                                     });
1180

1181
                     result.test_bin_eq(
1✔
1182
                        "TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
1✔
1183
                  })
1✔
1184

1185
            // TODO: The rest of this test vector requires 0-RTT which is not
1186
            //       yet implemented. For now we can only test the client's
1187
            //       ability to offer a session resumption via PSK.
1188
         };
2✔
1189
      }
2✔
1190

1191
      std::vector<Test::Result> hello_retry_request(const VarMap& vars) override {
1✔
1192
         auto add_extensions_and_sort = [flights = 0](Botan::TLS::Extensions& exts,
3✔
1193
                                                      Botan::TLS::Connection_Side side,
1194
                                                      Botan::TLS::Handshake_Type which_message) mutable {
1195
            if(which_message == Handshake_Type::ClientHello) {
2✔
1196
               ++flights;
2✔
1197

1198
               if(flights == 1) {
2✔
1199
                  add_renegotiation_extension(exts);
1✔
1200
               }
1201

1202
               // For some reason RFC8448 decided to require this (fairly obscure) extension
1203
               // in the second flight of the Client_Hello.
1204
               if(flights == 2) {
2✔
1205
                  exts.add(new Padding(175));  // NOLINT(*-owning-memory)
1✔
1206
               }
1207

1208
               sort_rfc8448_extensions(exts, side);
2✔
1209
            }
1210
         };
2✔
1211

1212
         // Fallback RNG is required to for blinding in ECDH with P-256
1213
         auto& fallback_rng = this->rng();
1✔
1214
         auto rng = std::make_unique<Fixed_Output_RNG>(fallback_rng);
1✔
1215

1216
         // 32 - client hello random
1217
         // 32 - eph. x25519 key pair
1218
         // 32 - eph. P-256 key pair
1219
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
1✔
1220

1221
         std::unique_ptr<Client_Context> ctx;
1✔
1222

1223
         return {
1✔
1224
            CHECK("Client Hello",
1225
                  [&](Test::Result& result) {
1✔
1226
                     ctx = std::make_unique<Client_Context>(std::move(rng),
1✔
1227
                                                            std::make_shared<RFC8448_Text_Policy>("rfc8448_hrr_client"),
2✔
1228
                                                            vars.get_req_u64("CurrentTimestamp"),
1✔
1229
                                                            add_extensions_and_sort);
1✔
1230
                     result.test_is_true("client not closed", !ctx->client.is_closed());
1✔
1231

1232
                     ctx->check_callback_invocations(result,
2✔
1233
                                                     "client hello prepared",
1234
                                                     {
1235
                                                        "tls_emit_data",
1236
                                                        "tls_inspect_handshake_msg_client_hello",
1237
                                                        "tls_modify_extensions_client_hello",
1238
                                                        "tls_generate_ephemeral_key",
1239
                                                        "tls_current_timestamp",
1240
                                                     });
1241

1242
                     result.test_bin_eq(
1✔
1243
                        "TLS client hello (1)", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
1✔
1244
                  }),
1✔
1245

1246
            CHECK("Hello Retry Request .. second Client Hello",
1247
                  [&](Test::Result& result) {
1✔
1248
                     result.require("ctx is available", ctx != nullptr);
1✔
1249
                     ctx->client.received_data(vars.get_req_bin("Record_HelloRetryRequest"));
1✔
1250

1251
                     ctx->check_callback_invocations(result,
2✔
1252
                                                     "hello retry request received",
1253
                                                     {
1254
                                                        "tls_emit_data",
1255
                                                        "tls_inspect_handshake_msg_hello_retry_request",
1256
                                                        "tls_examine_extensions_hello_retry_request",
1257
                                                        "tls_inspect_handshake_msg_client_hello",
1258
                                                        "tls_modify_extensions_client_hello",
1259
                                                        "tls_generate_ephemeral_key",
1260
                                                     });
1261

1262
                     result.test_bin_eq(
1✔
1263
                        "TLS client hello (2)", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_2"));
1✔
1264
                  }),
1✔
1265

1266
            CHECK("Server Hello",
1267
                  [&](Test::Result& result) {
1✔
1268
                     result.require("ctx is available", ctx != nullptr);
1✔
1269
                     ctx->client.received_data(vars.get_req_bin("Record_ServerHello"));
1✔
1270

1271
                     ctx->check_callback_invocations(result,
2✔
1272
                                                     "server hello received",
1273
                                                     {
1274
                                                        "tls_inspect_handshake_msg_server_hello",
1275
                                                        "tls_examine_extensions_server_hello",
1276
                                                        "tls_ephemeral_key_agreement",
1277
                                                     });
1278
                  }),
1✔
1279

1280
            CHECK("Server HS Messages .. Client Finished",
1281
                  [&](Test::Result& result) {
1✔
1282
                     result.require("ctx is available", ctx != nullptr);
1✔
1283
                     ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
1✔
1284

1285
                     ctx->check_callback_invocations(result,
2✔
1286
                                                     "encrypted handshake messages received",
1287
                                                     {"tls_inspect_handshake_msg_encrypted_extensions",
1288
                                                      "tls_inspect_handshake_msg_certificate",
1289
                                                      "tls_inspect_handshake_msg_certificate_verify",
1290
                                                      "tls_inspect_handshake_msg_finished",
1291
                                                      "tls_examine_extensions_encrypted_extensions",
1292
                                                      "tls_examine_extensions_certificate",
1293
                                                      "tls_emit_data",
1294
                                                      "tls_current_timestamp",
1295
                                                      "tls_session_established",
1296
                                                      "tls_session_activated",
1297
                                                      "tls_verify_cert_chain",
1298
                                                      "tls_verify_message"});
1299

1300
                     result.test_bin_eq(
1✔
1301
                        "client finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
1✔
1302
                  }),
1✔
1303

1304
            CHECK("Close Connection",
1305
                  [&](Test::Result& result) {
1✔
1306
                     result.require("ctx is available", ctx != nullptr);
1✔
1307
                     ctx->client.close();
1✔
1308
                     ctx->check_callback_invocations(
2✔
1309
                        result, "encrypted handshake messages received", {"tls_emit_data"});
1310
                     result.test_bin_eq(
1✔
1311
                        "client close notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
1✔
1312

1313
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
1✔
1314
                     ctx->check_callback_invocations(
2✔
1315
                        result, "encrypted handshake messages received", {"tls_alert", "tls_peer_closed_connection"});
1316

1317
                     result.test_is_true("connection is closed", ctx->client.is_closed());
1✔
1318
                  }),
1✔
1319
         };
6✔
1320
      }
2✔
1321

1322
      std::vector<Test::Result> client_authentication(const VarMap& vars) override {
1✔
1323
         auto rng = std::make_unique<Fixed_Output_RNG>("");
1✔
1324

1325
         // 32 - for client hello random
1326
         // 32 - for eph. x25519 key pair
1327
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
1✔
1328

1329
         auto add_extensions_and_sort = [&](Botan::TLS::Extensions& exts,
3✔
1330
                                            Botan::TLS::Connection_Side side,
1331
                                            Botan::TLS::Handshake_Type which_message) {
1332
            if(which_message == Handshake_Type::ClientHello) {
2✔
1333
               add_renegotiation_extension(exts);
1✔
1334
               sort_rfc8448_extensions(exts, side);
1✔
1335
            }
1336
         };
1337

1338
         std::unique_ptr<Client_Context> ctx;
1✔
1339

1340
         return {
1✔
1341
            CHECK("Client Hello",
1342
                  [&](Test::Result& result) {
1✔
1343
                     ctx = std::make_unique<Client_Context>(std::move(rng),
1✔
1344
                                                            std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
2✔
1345
                                                            vars.get_req_u64("CurrentTimestamp"),
1✔
1346
                                                            add_extensions_and_sort,
1347
                                                            std::nullopt,
1348
                                                            std::nullopt,
1349
                                                            make_mock_signatures(vars));
3✔
1350

1351
                     ctx->check_callback_invocations(result,
2✔
1352
                                                     "initial callbacks",
1353
                                                     {
1354
                                                        "tls_emit_data",
1355
                                                        "tls_inspect_handshake_msg_client_hello",
1356
                                                        "tls_modify_extensions_client_hello",
1357
                                                        "tls_generate_ephemeral_key",
1358
                                                        "tls_current_timestamp",
1359
                                                     });
1360

1361
                     result.test_bin_eq(
1✔
1362
                        "Client Hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
1✔
1363
                  }),
1✔
1364

1365
            CHECK("Server Hello",
1366
                  [&](auto& result) {
1✔
1367
                     result.require("ctx is available", ctx != nullptr);
1✔
1368
                     ctx->client.received_data(vars.get_req_bin("Record_ServerHello"));
1✔
1369

1370
                     ctx->check_callback_invocations(result,
2✔
1371
                                                     "callbacks after server hello",
1372
                                                     {
1373
                                                        "tls_examine_extensions_server_hello",
1374
                                                        "tls_inspect_handshake_msg_server_hello",
1375
                                                        "tls_ephemeral_key_agreement",
1376
                                                     });
1377
                  }),
1✔
1378

1379
            CHECK("other handshake messages and client auth",
1380
                  [&](Test::Result& result) {
1✔
1381
                     result.require("ctx is available", ctx != nullptr);
1✔
1382
                     ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
1✔
1383

1384
                     ctx->check_callback_invocations(result,
2✔
1385
                                                     "signing callbacks invoked",
1386
                                                     {
1387
                                                        "tls_sign_message",
1388
                                                        "tls_emit_data",
1389
                                                        "tls_examine_extensions_encrypted_extensions",
1390
                                                        "tls_examine_extensions_certificate",
1391
                                                        "tls_examine_extensions_certificate_request",
1392
                                                        "tls_modify_extensions_certificate",
1393
                                                        "tls_inspect_handshake_msg_certificate",
1394
                                                        "tls_inspect_handshake_msg_certificate_request",
1395
                                                        "tls_inspect_handshake_msg_certificate_verify",
1396
                                                        "tls_inspect_handshake_msg_encrypted_extensions",
1397
                                                        "tls_inspect_handshake_msg_finished",
1398
                                                        "tls_current_timestamp",
1399
                                                        "tls_session_established",
1400
                                                        "tls_session_activated",
1401
                                                        "tls_verify_cert_chain",
1402
                                                        "tls_verify_message",
1403
                                                     });
1404

1405
                     // ClientFinished contains the entire coalesced client authentication flight
1406
                     // Messages: Certificate, CertificateVerify, Finished
1407
                     result.test_bin_eq(
1✔
1408
                        "Client Auth and Finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
1✔
1409
                  }),
1✔
1410

1411
            CHECK("Close Connection",
1412
                  [&](Test::Result& result) {
1✔
1413
                     result.require("ctx is available", ctx != nullptr);
1✔
1414
                     ctx->client.close();
1✔
1415
                     result.test_bin_eq(
1✔
1416
                        "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
1✔
1417

1418
                     ctx->check_callback_invocations(result,
2✔
1419
                                                     "after sending close notify",
1420
                                                     {
1421
                                                        "tls_emit_data",
1422
                                                     });
1423

1424
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
1✔
1425
                     result.test_is_true("connection closed", ctx->client.is_closed());
1✔
1426

1427
                     ctx->check_callback_invocations(
2✔
1428
                        result, "after receiving close notify", {"tls_alert", "tls_peer_closed_connection"});
1429
                  }),
1✔
1430
         };
5✔
1431
      }
2✔
1432

1433
      std::vector<Test::Result> middlebox_compatibility(const VarMap& vars) override {
1✔
1434
         auto rng = std::make_unique<Fixed_Output_RNG>("");
1✔
1435

1436
         // 32 - client hello random
1437
         // 32 - legacy session ID
1438
         // 32 - eph. x25519 key pair
1439
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
1✔
1440

1441
         auto add_extensions_and_sort = [&](Botan::TLS::Extensions& exts,
2✔
1442
                                            Botan::TLS::Connection_Side side,
1443
                                            Botan::TLS::Handshake_Type which_message) {
1444
            if(which_message == Handshake_Type::ClientHello) {
1✔
1445
               add_renegotiation_extension(exts);
1✔
1446
               sort_rfc8448_extensions(exts, side);
1✔
1447
            }
1448
         };
1449

1450
         std::unique_ptr<Client_Context> ctx;
1✔
1451

1452
         return {
1✔
1453
            CHECK(
1454
               "Client Hello",
1455
               [&](Test::Result& result) {
1✔
1456
                  ctx = std::make_unique<Client_Context>(std::move(rng),
1✔
1457
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_compat_client"),
2✔
1458
                                                         vars.get_req_u64("CurrentTimestamp"),
1✔
1459
                                                         add_extensions_and_sort);
1✔
1460

1461
                  result.test_bin_eq("Client Hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
1✔
1462

1463
                  ctx->check_callback_invocations(result,
2✔
1464
                                                  "client hello prepared",
1465
                                                  {
1466
                                                     "tls_emit_data",
1467
                                                     "tls_inspect_handshake_msg_client_hello",
1468
                                                     "tls_modify_extensions_client_hello",
1469
                                                     "tls_generate_ephemeral_key",
1470
                                                     "tls_current_timestamp",
1471
                                                  });
1472
               }),
1✔
1473

1474
            CHECK("Server Hello + other handshake messages",
1475
                  [&](Test::Result& result) {
1✔
1476
                     result.require("ctx is available", ctx != nullptr);
1✔
1477
                     ctx->client.received_data(
2✔
1478
                        Botan::concat(vars.get_req_bin("Record_ServerHello"),
2✔
1479
                                      // ServerHandshakeMessages contains the expected ChangeCipherSpec record
1480
                                      vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1481

1482
                     ctx->check_callback_invocations(result,
2✔
1483
                                                     "callbacks after server's first flight",
1484
                                                     {
1485
                                                        "tls_inspect_handshake_msg_server_hello",
1486
                                                        "tls_inspect_handshake_msg_encrypted_extensions",
1487
                                                        "tls_inspect_handshake_msg_certificate",
1488
                                                        "tls_inspect_handshake_msg_certificate_verify",
1489
                                                        "tls_inspect_handshake_msg_finished",
1490
                                                        "tls_examine_extensions_server_hello",
1491
                                                        "tls_examine_extensions_encrypted_extensions",
1492
                                                        "tls_examine_extensions_certificate",
1493
                                                        "tls_emit_data",
1494
                                                        "tls_current_timestamp",
1495
                                                        "tls_session_established",
1496
                                                        "tls_session_activated",
1497
                                                        "tls_verify_cert_chain",
1498
                                                        "tls_verify_message",
1499
                                                        "tls_ephemeral_key_agreement",
1500
                                                     });
1501

1502
                     result.test_bin_eq("CCS + Client Finished",
1✔
1503
                                        ctx->pull_send_buffer(),
1✔
1504
                                        // ClientFinished contains the expected ChangeCipherSpec record
1505
                                        vars.get_req_bin("Record_ClientFinished"));
2✔
1506

1507
                     result.test_is_true("client is ready to send application traffic", ctx->client.is_active());
1✔
1508
                     result.test_is_true("handshake is complete", ctx->client.is_handshake_complete());
1✔
1509
                  }),
1✔
1510

1511
            CHECK("Close connection",
1512
                  [&](Test::Result& result) {
1✔
1513
                     result.require("ctx is available", ctx != nullptr);
1✔
1514
                     ctx->client.close();
1✔
1515

1516
                     result.test_bin_eq(
1✔
1517
                        "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
1✔
1518

1519
                     result.require("client cannot send application traffic anymore", !ctx->client.is_active());
1✔
1520
                     result.require("client is not fully closed yet", !ctx->client.is_closed());
1✔
1521
                     result.test_is_true("handshake stays completed", ctx->client.is_handshake_complete());
1✔
1522

1523
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
1✔
1524

1525
                     result.test_is_true("client connection was terminated", ctx->client.is_closed());
1✔
1526
                  }),
1✔
1527
         };
4✔
1528
      }
2✔
1529

1530
      std::vector<Test::Result> externally_provided_psk_with_ephemeral_key(const VarMap& vars) override {
1✔
1531
         auto rng = std::make_unique<Fixed_Output_RNG>("");
1✔
1532

1533
         // 32 - for client hello random
1534
         // 32 - for KeyShare (eph. x25519 key pair)
1535
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
1✔
1536

1537
         auto sort_our_extensions = [](Botan::TLS::Extensions& exts,
2✔
1538
                                       Botan::TLS::Connection_Side /* side */,
1539
                                       Botan::TLS::Handshake_Type /* which_message */) {
1540
            // This is the order of extensions when we first introduced the PSK
1541
            // implementation and generated the transcript. To stay compatible
1542
            // with the now hard-coded transcript, we pin the extension order.
1543
            sort_extensions(exts,
1✔
1544
                            {
1545
                               Botan::TLS::Extension_Code::ServerNameIndication,
1546
                               Botan::TLS::Extension_Code::SupportedGroups,
1547
                               Botan::TLS::Extension_Code::KeyShare,
1548
                               Botan::TLS::Extension_Code::SupportedVersions,
1549
                               Botan::TLS::Extension_Code::SignatureAlgorithms,
1550
                               Botan::TLS::Extension_Code::PskKeyExchangeModes,
1551
                               Botan::TLS::Extension_Code::RecordSizeLimit,
1552
                               Botan::TLS::Extension_Code::PresharedKey,
1553
                            });
1554
         };
1✔
1555

1556
         std::unique_ptr<Client_Context> ctx;
1✔
1557

1558
         return {
1✔
1559
            CHECK("Client Hello",
1560
                  [&](Test::Result& result) {
1✔
1561
                     ctx = std::make_unique<Client_Context>(
1✔
1562
                        std::move(rng),
1563
                        std::make_shared<RFC8448_Text_Policy>("rfc8448_psk_dhe", false /* no rfc8448 */),
2✔
1564
                        vars.get_req_u64("CurrentTimestamp"),
1✔
1565
                        sort_our_extensions,
1566
                        std::nullopt,
1567
                        ExternalPSK(vars.get_req_str("PskIdentity"),
2✔
1568
                                    vars.get_req_str("PskPRF"),
2✔
1569
                                    lock(vars.get_req_bin("PskSecret"))));
4✔
1570

1571
                     result.test_is_true("client not closed", !ctx->client.is_closed());
1✔
1572
                     ctx->check_callback_invocations(result,
2✔
1573
                                                     "client hello prepared",
1574
                                                     {
1575
                                                        "tls_emit_data",
1576
                                                        "tls_inspect_handshake_msg_client_hello",
1577
                                                        "tls_modify_extensions_client_hello",
1578
                                                        "tls_current_timestamp",
1579
                                                        "tls_generate_ephemeral_key",
1580
                                                     });
1581

1582
                     result.test_bin_eq(
1✔
1583
                        "TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
1✔
1584
                  }),
1✔
1585

1586
            CHECK("Server Hello",
1587
                  [&](Test::Result& result) {
1✔
1588
                     result.require("ctx is available", ctx != nullptr);
1✔
1589
                     const auto server_hello = vars.get_req_bin("Record_ServerHello");
1✔
1590
                     ctx->client.received_data(server_hello);
1✔
1591
                     ctx->check_callback_invocations(result,
2✔
1592
                                                     "server hello received",
1593
                                                     {"tls_inspect_handshake_msg_server_hello",
1594
                                                      "tls_examine_extensions_server_hello",
1595
                                                      "tls_ephemeral_key_agreement"});
1596

1597
                     result.test_is_true("client is not yet active", !ctx->client.is_active());
1✔
1598
                     result.test_is_true("handshake is not yet complete", !ctx->client.is_handshake_complete());
1✔
1599
                  }),
1✔
1600

1601
            CHECK(
1602
               "Server HS messages .. Client Finished",
1603
               [&](Test::Result& result) {
1✔
1604
                  result.require("ctx is available", ctx != nullptr);
1✔
1605
                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
1✔
1606

1607
                  ctx->check_callback_invocations(result,
2✔
1608
                                                  "encrypted handshake messages received",
1609
                                                  {"tls_inspect_handshake_msg_encrypted_extensions",
1610
                                                   "tls_inspect_handshake_msg_finished",
1611
                                                   "tls_examine_extensions_encrypted_extensions",
1612
                                                   "tls_emit_data",
1613
                                                   "tls_current_timestamp",
1614
                                                   "tls_session_established",
1615
                                                   "tls_session_activated"});
1616
                  result.require("PSK negotiated", ctx->psk_identity_negotiated() == vars.get_req_str("PskIdentity"));
1✔
1617
                  result.require("client is active", ctx->client.is_active());
1✔
1618
                  result.test_is_true("handshake is complete", ctx->client.is_handshake_complete());
1✔
1619

1620
                  result.test_bin_eq(
1✔
1621
                     "correct handshake finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
1✔
1622
               }),
1✔
1623

1624
            CHECK("Send Application Data",
1625
                  [&](Test::Result& result) {
1✔
1626
                     result.require("ctx is available", ctx != nullptr);
1✔
1627
                     ctx->send(vars.get_req_bin("Client_AppData"));
2✔
1628

1629
                     ctx->check_callback_invocations(result, "application data sent", {"tls_emit_data"});
2✔
1630

1631
                     result.test_bin_eq("correct client application data",
1✔
1632
                                        ctx->pull_send_buffer(),
1✔
1633
                                        vars.get_req_bin("Record_Client_AppData"));
2✔
1634
                  }),
1✔
1635

1636
            CHECK("Receive Application Data",
1637
                  [&](Test::Result& result) {
1✔
1638
                     result.require("ctx is available", ctx != nullptr);
1✔
1639
                     ctx->client.received_data(vars.get_req_bin("Record_Server_AppData"));
1✔
1640

1641
                     ctx->check_callback_invocations(result, "application data sent", {"tls_record_received"});
2✔
1642

1643
                     const auto rcvd = ctx->pull_receive_buffer();
1✔
1644
                     result.test_bin_eq("decrypted application traffic", rcvd, vars.get_req_bin("Server_AppData"));
1✔
1645
                     result.test_u64_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
1✔
1646
                  }),
1✔
1647

1648
            CHECK("Close Connection",
1649
                  [&](Test::Result& result) {
1✔
1650
                     result.require("ctx is available", ctx != nullptr);
1✔
1651
                     ctx->client.close();
1✔
1652

1653
                     result.test_bin_eq(
1✔
1654
                        "close payload", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
1✔
1655
                     ctx->check_callback_invocations(result, "CLOSE_NOTIFY sent", {"tls_emit_data"});
2✔
1656

1657
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
1✔
1658
                     ctx->check_callback_invocations(
2✔
1659
                        result, "CLOSE_NOTIFY received", {"tls_alert", "tls_peer_closed_connection"});
1660

1661
                     result.test_is_true("connection is closed", ctx->client.is_closed());
1✔
1662
                  }),
1✔
1663
         };
7✔
1664
      }
2✔
1665

1666
      std::vector<Test::Result> raw_public_key_with_client_authentication(const VarMap& vars) override {
1✔
1667
         auto rng = std::make_unique<Fixed_Output_RNG>("");
1✔
1668

1669
         // 32 - for client hello random
1670
         // 32 - for KeyShare (eph. x25519 key pair)
1671
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
1✔
1672

1673
         auto sort_our_extensions = [&](Botan::TLS::Extensions& exts,
3✔
1674
                                        Botan::TLS::Connection_Side /* side */,
1675
                                        Botan::TLS::Handshake_Type /* which_message */) {
1676
            // This is the order of extensions when we first introduced the raw
1677
            // public key authentication implementation and generated the transcript.
1678
            // To stay compatible with the now hard-coded transcript, we pin the
1679
            // extension order.
1680
            sort_extensions(exts,
2✔
1681
                            {
1682
                               Botan::TLS::Extension_Code::ServerNameIndication,
1683
                               Botan::TLS::Extension_Code::SupportedGroups,
1684
                               Botan::TLS::Extension_Code::KeyShare,
1685
                               Botan::TLS::Extension_Code::SupportedVersions,
1686
                               Botan::TLS::Extension_Code::SignatureAlgorithms,
1687
                               Botan::TLS::Extension_Code::PskKeyExchangeModes,
1688
                               Botan::TLS::Extension_Code::RecordSizeLimit,
1689
                               Botan::TLS::Extension_Code::ClientCertificateType,
1690
                               Botan::TLS::Extension_Code::ServerCertificateType,
1691
                            });
1692
         };
2✔
1693

1694
         std::unique_ptr<Client_Context> ctx;
1✔
1695

1696
         return {
1✔
1697
            CHECK("Client Hello",
1698
                  [&](Test::Result& result) {
1✔
1699
                     ctx = std::make_unique<Client_Context>(std::move(rng),
1✔
1700
                                                            std::make_shared<RFC8448_Text_Policy>("rfc8448_rawpubkey"),
2✔
1701
                                                            vars.get_req_u64("CurrentTimestamp"),
1✔
1702
                                                            sort_our_extensions,
1703
                                                            std::nullopt,
1704
                                                            std::nullopt,
1705
                                                            make_mock_signatures(vars));
3✔
1706

1707
                     ctx->check_callback_invocations(result,
2✔
1708
                                                     "initial callbacks",
1709
                                                     {
1710
                                                        "tls_emit_data",
1711
                                                        "tls_inspect_handshake_msg_client_hello",
1712
                                                        "tls_modify_extensions_client_hello",
1713
                                                        "tls_generate_ephemeral_key",
1714
                                                        "tls_current_timestamp",
1715
                                                     });
1716

1717
                     result.test_bin_eq(
1✔
1718
                        "Client Hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
1✔
1719
                  }),
1✔
1720

1721
            CHECK("Server Hello",
1722
                  [&](auto& result) {
1✔
1723
                     result.require("ctx is available", ctx != nullptr);
1✔
1724
                     ctx->client.received_data(vars.get_req_bin("Record_ServerHello"));
1✔
1725

1726
                     ctx->check_callback_invocations(result,
2✔
1727
                                                     "callbacks after server hello",
1728
                                                     {
1729
                                                        "tls_examine_extensions_server_hello",
1730
                                                        "tls_inspect_handshake_msg_server_hello",
1731
                                                        "tls_ephemeral_key_agreement",
1732
                                                     });
1733
                  }),
1✔
1734

1735
            CHECK("other handshake messages and client auth",
1736
                  [&](Test::Result& result) {
1✔
1737
                     result.require("ctx is available", ctx != nullptr);
1✔
1738
                     ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
1✔
1739

1740
                     ctx->check_callback_invocations(result,
2✔
1741
                                                     "signing callbacks invoked",
1742
                                                     {
1743
                                                        "tls_sign_message",
1744
                                                        "tls_emit_data",
1745
                                                        "tls_examine_extensions_encrypted_extensions",
1746
                                                        "tls_examine_extensions_certificate",
1747
                                                        "tls_examine_extensions_certificate_request",
1748
                                                        "tls_modify_extensions_certificate",
1749
                                                        "tls_inspect_handshake_msg_certificate",
1750
                                                        "tls_inspect_handshake_msg_certificate_request",
1751
                                                        "tls_inspect_handshake_msg_certificate_verify",
1752
                                                        "tls_inspect_handshake_msg_encrypted_extensions",
1753
                                                        "tls_inspect_handshake_msg_finished",
1754
                                                        "tls_current_timestamp",
1755
                                                        "tls_session_established",
1756
                                                        "tls_session_activated",
1757
                                                        "tls_verify_raw_public_key",
1758
                                                        "tls_verify_message",
1759
                                                     });
1760

1761
                     const auto raw_pk = ctx->client.peer_raw_public_key();
1✔
1762
                     result.test_is_true(
1✔
1763
                        "Received server's raw public key",
1764
                        raw_pk && raw_pk->fingerprint_public() == server_raw_public_key_pair()->fingerprint_public());
5✔
1765

1766
                     // ClientFinished contains the entire coalesced client authentication flight
1767
                     // Messages: Certificate, CertificateVerify, Finished
1768
                     result.test_bin_eq(
1✔
1769
                        "Client Auth and Finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
1✔
1770
                  }),
1✔
1771

1772
            CHECK("Close Connection",
1773
                  [&](Test::Result& result) {
1✔
1774
                     result.require("ctx is available", ctx != nullptr);
1✔
1775
                     ctx->client.close();
1✔
1776
                     result.test_bin_eq(
1✔
1777
                        "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
1✔
1778

1779
                     ctx->check_callback_invocations(result,
2✔
1780
                                                     "after sending close notify",
1781
                                                     {
1782
                                                        "tls_emit_data",
1783
                                                     });
1784

1785
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
1✔
1786
                     result.test_is_true("connection closed", ctx->client.is_closed());
1✔
1787

1788
                     ctx->check_callback_invocations(
2✔
1789
                        result, "after receiving close notify", {"tls_alert", "tls_peer_closed_connection"});
1790
                  }),
1✔
1791
         };
5✔
1792
      }
2✔
1793
};
1794

1795
class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 {
1✔
1796
   private:
1797
      std::string side() const override { return "Server"; }
7✔
1798

1799
      std::vector<Test::Result> simple_1_rtt(const VarMap& vars) override {
1✔
1800
         auto rng = std::make_unique<Fixed_Output_RNG>("");
1✔
1801

1802
         // 32 - for server hello random
1803
         // 32 - for KeyShare (eph. x25519 key pair)  --  I guess?
1804
         //  4 - for ticket_age_add (in New Session Ticket)
1805
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
1✔
1806

1807
         std::unique_ptr<Server_Context> ctx;
1✔
1808

1809
         return {
1✔
1810
            CHECK("Send Client Hello",
1811
                  [&](Test::Result& result) {
1✔
1812
                     auto add_early_data_and_sort = [&](Botan::TLS::Extensions& exts,
5✔
1813
                                                        Botan::TLS::Connection_Side side,
1814
                                                        Botan::TLS::Handshake_Type type) {
1815
                        if(type == Handshake_Type::NewSessionTicket) {
4✔
1816
                           exts.add(new EarlyDataIndication(1024));  // NOLINT(*-owning-memory)
1✔
1817
                        }
1818
                        sort_rfc8448_extensions(exts, side, type);
4✔
1819
                     };
4✔
1820

1821
                     ctx = std::make_unique<Server_Context>(
1✔
1822
                        std::move(rng),
1823
                        std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
2✔
1824
                        vars.get_req_u64("CurrentTimestamp"),
1✔
1825
                        add_early_data_and_sort,
1826
                        make_mock_signatures(vars),
1✔
1827
                        false,
1✔
1828
                        std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
4✔
1829
                                  Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1830
                     result.test_is_true("server not closed", !ctx->server.is_closed());
1✔
1831

1832
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
1✔
1833

1834
                     ctx->check_callback_invocations(result,
2✔
1835
                                                     "client hello received",
1836
                                                     {"tls_emit_data",
1837
                                                      "tls_examine_extensions_client_hello",
1838
                                                      "tls_modify_extensions_server_hello",
1839
                                                      "tls_modify_extensions_encrypted_extensions",
1840
                                                      "tls_modify_extensions_certificate",
1841
                                                      "tls_sign_message",
1842
                                                      "tls_generate_ephemeral_key",
1843
                                                      "tls_ephemeral_key_agreement",
1844
                                                      "tls_inspect_handshake_msg_client_hello",
1845
                                                      "tls_inspect_handshake_msg_server_hello",
1846
                                                      "tls_inspect_handshake_msg_encrypted_extensions",
1847
                                                      "tls_inspect_handshake_msg_certificate",
1848
                                                      "tls_inspect_handshake_msg_certificate_verify",
1849
                                                      "tls_inspect_handshake_msg_finished"});
1850
                  }),
1✔
1851

1852
            CHECK("Verify generated messages in server's first flight",
1853
                  [&](Test::Result& result) {
1✔
1854
                     result.require("ctx is available", ctx != nullptr);
1✔
1855
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
1856

1857
                     result.test_bin_eq("Server Hello",
2✔
1858
                                        msgs.at("server_hello")[0],
1✔
1859
                                        strip_message_header(vars.get_opt_bin("Message_ServerHello")));
2✔
1860
                     result.test_bin_eq("Encrypted Extensions",
2✔
1861
                                        msgs.at("encrypted_extensions")[0],
1✔
1862
                                        strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
2✔
1863
                     result.test_bin_eq("Certificate",
2✔
1864
                                        msgs.at("certificate")[0],
1✔
1865
                                        strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
2✔
1866
                     result.test_bin_eq("CertificateVerify",
2✔
1867
                                        msgs.at("certificate_verify")[0],
1✔
1868
                                        strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
2✔
1869

1870
                     result.test_bin_eq("Server's entire first flight",
1✔
1871
                                        ctx->pull_send_buffer(),
1✔
1872
                                        concat(vars.get_req_bin("Record_ServerHello"),
3✔
1873
                                               vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1874

1875
                     // Note: is_active() defines that we can send application data.
1876
                     //       RFC 8446 Section 4.4.4 explicitly allows that for servers
1877
                     //       that did not receive the client's Finished message, yet.
1878
                     //       However, before receiving and validating this message,
1879
                     //       the handshake is not yet finished.
1880
                     result.test_is_true("Server can now send application data", ctx->server.is_active());
1✔
1881
                     result.test_is_true("handshake is not yet complete", !ctx->server.is_handshake_complete());
1✔
1882
                  }),
1✔
1883

1884
            CHECK("Send Client Finished",
1885
                  [&](Test::Result& result) {
1✔
1886
                     result.require("ctx is available", ctx != nullptr);
1✔
1887
                     ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
1✔
1888

1889
                     ctx->check_callback_invocations(result,
2✔
1890
                                                     "client finished received",
1891
                                                     {"tls_inspect_handshake_msg_finished",
1892
                                                      "tls_current_timestamp",
1893
                                                      "tls_session_established",
1894
                                                      "tls_session_activated"});
1895
                  }),
1✔
1896

1897
            CHECK("Send Session Ticket",
1898
                  [&](Test::Result& result) {
1✔
1899
                     result.require("ctx is available", ctx != nullptr);
1✔
1900
                     const auto new_tickets = ctx->server.send_new_session_tickets(1);
1✔
1901

1902
                     result.test_sz_eq("session ticket was sent", new_tickets, 1);
1✔
1903

1904
                     ctx->check_callback_invocations(result,
2✔
1905
                                                     "issued new session ticket",
1906
                                                     {"tls_inspect_handshake_msg_new_session_ticket",
1907
                                                      "tls_current_timestamp",
1908
                                                      "tls_emit_data",
1909
                                                      "tls_modify_extensions_new_session_ticket",
1910
                                                      "tls_should_persist_resumption_information"});
1911
                  }),
1✔
1912

1913
            CHECK("Verify generated new session ticket message",
1914
                  [&](Test::Result& result) {
1✔
1915
                     result.require("ctx is available", ctx != nullptr);
1✔
1916
                     result.test_bin_eq(
1✔
1917
                        "New Session Ticket", ctx->pull_send_buffer(), vars.get_req_bin("Record_NewSessionTicket"));
1✔
1918
                  }),
1✔
1919

1920
            CHECK("Receive Application Data",
1921
                  [&](Test::Result& result) {
1✔
1922
                     result.require("ctx is available", ctx != nullptr);
1✔
1923
                     ctx->server.received_data(vars.get_req_bin("Record_Client_AppData"));
1✔
1924
                     ctx->check_callback_invocations(result, "application data received", {"tls_record_received"});
2✔
1925

1926
                     const auto rcvd = ctx->pull_receive_buffer();
1✔
1927
                     result.test_bin_eq("decrypted application traffic", rcvd, vars.get_req_bin("Client_AppData"));
1✔
1928
                     result.test_u64_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
1✔
1929
                  }),
1✔
1930

1931
            CHECK("Send Application Data",
1932
                  [&](Test::Result& result) {
1✔
1933
                     result.require("ctx is available", ctx != nullptr);
1✔
1934
                     ctx->send(vars.get_req_bin("Server_AppData"));
2✔
1935

1936
                     ctx->check_callback_invocations(result, "application data sent", {"tls_emit_data"});
2✔
1937

1938
                     result.test_bin_eq("correct server application data",
1✔
1939
                                        ctx->pull_send_buffer(),
1✔
1940
                                        vars.get_req_bin("Record_Server_AppData"));
2✔
1941
                  }),
1✔
1942

1943
            CHECK("Receive Client's close_notify",
1944
                  [&](Test::Result& result) {
1✔
1945
                     result.require("ctx is available", ctx != nullptr);
1✔
1946
                     ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
1✔
1947

1948
                     ctx->check_callback_invocations(
2✔
1949
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
1950

1951
                     result.test_is_true("connection is not yet closed", !ctx->server.is_closed());
1✔
1952
                     result.test_is_true("connection is still active", ctx->server.is_active());
1✔
1953
                     result.test_is_true("handshake is still finished", ctx->server.is_handshake_complete());
1✔
1954
                  }),
1✔
1955

1956
            CHECK("Expect Server close_notify",
1957
                  [&](Test::Result& result) {
1✔
1958
                     result.require("ctx is available", ctx != nullptr);
1✔
1959
                     ctx->server.close();
1✔
1960

1961
                     result.test_is_true("connection is now inactive", !ctx->server.is_active());
1✔
1962
                     result.test_is_true("connection is now closed", ctx->server.is_closed());
1✔
1963
                     result.test_is_true("handshake is still finished", ctx->server.is_handshake_complete());
1✔
1964
                     result.test_bin_eq("Server's close notify",
1✔
1965
                                        ctx->pull_send_buffer(),
1✔
1966
                                        vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1967
                  }),
1✔
1968
         };
10✔
1969
      }
2✔
1970

1971
      std::vector<Test::Result> resumed_handshake_with_0_rtt(const VarMap& vars) override {
1✔
1972
         auto rng = std::make_unique<Fixed_Output_RNG>();
1✔
1973

1974
         // 32 - for server hello random
1975
         // 32 - for KeyShare (eph. x25519 key pair)
1976
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
1✔
1977

1978
         std::unique_ptr<Server_Context> ctx;
1✔
1979

1980
         return {
1✔
1981
            CHECK("Receive Client Hello",
1982
                  [&](Test::Result& result) {
1✔
1983
                     auto add_cookie_and_sort = [&](Botan::TLS::Extensions& exts,
3✔
1984
                                                    Botan::TLS::Connection_Side side,
1985
                                                    Botan::TLS::Handshake_Type type) {
1986
                        if(type == Handshake_Type::EncryptedExtensions) {
2✔
1987
                           exts.add(new EarlyDataIndication());  // NOLINT(*-owning-memory)
1✔
1988
                        }
1989
                        sort_rfc8448_extensions(exts, side, type);
2✔
1990
                     };
2✔
1991

1992
                     ctx = std::make_unique<Server_Context>(
1✔
1993
                        std::move(rng),
1994
                        std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
2✔
1995
                        vars.get_req_u64("CurrentTimestamp"),
1✔
1996
                        add_cookie_and_sort,
1997
                        make_mock_signatures(vars),
1✔
1998
                        false,
1✔
1999
                        std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
4✔
2000
                                  Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
2001
                     result.test_is_true("server not closed", !ctx->server.is_closed());
1✔
2002

2003
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
1✔
2004

2005
                     ctx->check_callback_invocations(result,
2✔
2006
                                                     "client hello received",
2007
                                                     {
2008
                                                        "tls_emit_data",
2009
                                                        "tls_current_timestamp",
2010
                                                        "tls_generate_ephemeral_key",
2011
                                                        "tls_ephemeral_key_agreement",
2012
                                                        "tls_examine_extensions_client_hello",
2013
                                                        "tls_modify_extensions_server_hello",
2014
                                                        "tls_modify_extensions_encrypted_extensions",
2015
                                                        "tls_inspect_handshake_msg_client_hello",
2016
                                                        "tls_inspect_handshake_msg_server_hello",
2017
                                                        "tls_inspect_handshake_msg_encrypted_extensions",
2018
                                                        "tls_inspect_handshake_msg_finished",
2019
                                                     });
2020
                  }),
1✔
2021

2022
            CHECK("Verify generated messages in server's first flight",
2023
                  [&](Test::Result& result) {
1✔
2024
                     result.require("ctx is available", ctx != nullptr);
1✔
2025
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
2026

2027
                     result.test_bin_eq("Server Hello",
2✔
2028
                                        msgs.at("server_hello")[0],
1✔
2029
                                        strip_message_header(vars.get_opt_bin("Message_ServerHello")));
2✔
2030
                     result.test_bin_eq("Encrypted Extensions",
2✔
2031
                                        msgs.at("encrypted_extensions")[0],
1✔
2032
                                        strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
2✔
2033

2034
                     result.test_bin_eq("Server's entire first flight",
1✔
2035
                                        ctx->pull_send_buffer(),
1✔
2036
                                        concat(vars.get_req_bin("Record_ServerHello"),
3✔
2037
                                               vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2038

2039
                     // Note: is_active() defines that we can send application data.
2040
                     //       RFC 8446 Section 4.4.4 explicitly allows that for servers
2041
                     //       that did not receive the client's Finished message, yet.
2042
                     //       However, before receiving and validating this message,
2043
                     //       the handshake is not yet finished.
2044
                     result.test_is_true("Server can now send application data", ctx->server.is_active());
1✔
2045
                     result.test_is_true("handshake is not yet complete", !ctx->server.is_handshake_complete());
1✔
2046
                  }),
1✔
2047

2048
            // TODO: The rest of this test vector requires 0-RTT which is not
2049
            //       yet implemented. For now we can only test the server's
2050
            //       ability to acknowledge a session resumption via PSK.
2051
         };
3✔
2052
      }
2✔
2053

2054
      std::vector<Test::Result> hello_retry_request(const VarMap& vars) override {
1✔
2055
         // Fallback RNG is required to for blinding in ECDH with P-256
2056
         auto& fallback_rng = this->rng();
1✔
2057
         auto rng = std::make_unique<Fixed_Output_RNG>(fallback_rng);
1✔
2058

2059
         // 32 - for server hello random
2060
         // 32 - for KeyShare (eph. P-256 key pair)
2061
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
1✔
2062

2063
         std::unique_ptr<Server_Context> ctx;
1✔
2064

2065
         return {
1✔
2066
            CHECK("Receive Client Hello",
2067
                  [&](Test::Result& result) {
1✔
2068
                     auto add_cookie_and_sort = [&](Botan::TLS::Extensions& exts,
5✔
2069
                                                    Botan::TLS::Connection_Side side,
2070
                                                    Botan::TLS::Handshake_Type type) {
2071
                        if(type == Handshake_Type::HelloRetryRequest) {
4✔
2072
                           // This cookie needs to be mocked into the HRR since RFC 8448 contains it.
2073
                           exts.add(
1✔
2074
                              new Cookie(vars.get_opt_bin("HelloRetryRequest_Cookie")));  // NOLINT(*-owning-memory)
2✔
2075
                        }
2076
                        sort_rfc8448_extensions(exts, side, type);
4✔
2077
                     };
4✔
2078

2079
                     ctx = std::make_unique<Server_Context>(std::move(rng),
1✔
2080
                                                            std::make_shared<RFC8448_Text_Policy>("rfc8448_hrr_server"),
2✔
2081
                                                            vars.get_req_u64("CurrentTimestamp"),
1✔
2082
                                                            add_cookie_and_sort,
2083
                                                            make_mock_signatures(vars));
3✔
2084
                     result.test_is_true("server not closed", !ctx->server.is_closed());
1✔
2085

2086
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
1✔
2087

2088
                     ctx->check_callback_invocations(result,
2✔
2089
                                                     "client hello received",
2090
                                                     {"tls_emit_data",
2091
                                                      "tls_examine_extensions_client_hello",
2092
                                                      "tls_modify_extensions_hello_retry_request",
2093
                                                      "tls_inspect_handshake_msg_client_hello",
2094
                                                      "tls_inspect_handshake_msg_hello_retry_request"});
2095
                  }),
1✔
2096

2097
            CHECK("Verify generated Hello Retry Request message",
2098
                  [&](Test::Result& result) {
1✔
2099
                     result.require("ctx is available", ctx != nullptr);
1✔
2100
                     result.test_bin_eq("Server's Hello Retry Request record",
1✔
2101
                                        ctx->pull_send_buffer(),
1✔
2102
                                        vars.get_req_bin("Record_HelloRetryRequest"));
2✔
2103
                     result.test_is_true("TLS handshake not yet finished", !ctx->server.is_active());
1✔
2104
                     result.test_is_true("handshake is not yet complete", !ctx->server.is_handshake_complete());
1✔
2105
                  }),
1✔
2106

2107
            CHECK("Receive updated Client Hello message",
2108
                  [&](Test::Result& result) {
1✔
2109
                     result.require("ctx is available", ctx != nullptr);
1✔
2110
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_2"));
1✔
2111

2112
                     ctx->check_callback_invocations(result,
2✔
2113
                                                     "updated client hello received",
2114
                                                     {"tls_emit_data",
2115
                                                      "tls_examine_extensions_client_hello",
2116
                                                      "tls_modify_extensions_server_hello",
2117
                                                      "tls_modify_extensions_encrypted_extensions",
2118
                                                      "tls_modify_extensions_certificate",
2119
                                                      "tls_sign_message",
2120
                                                      "tls_generate_ephemeral_key",
2121
                                                      "tls_ephemeral_key_agreement",
2122
                                                      "tls_inspect_handshake_msg_client_hello",
2123
                                                      "tls_inspect_handshake_msg_server_hello",
2124
                                                      "tls_inspect_handshake_msg_encrypted_extensions",
2125
                                                      "tls_inspect_handshake_msg_certificate",
2126
                                                      "tls_inspect_handshake_msg_certificate_verify",
2127
                                                      "tls_inspect_handshake_msg_finished"});
2128
                  }),
1✔
2129

2130
            CHECK("Verify generated messages in server's second flight",
2131
                  [&](Test::Result& result) {
1✔
2132
                     result.require("ctx is available", ctx != nullptr);
1✔
2133
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
2134

2135
                     result.test_bin_eq("Server Hello",
2✔
2136
                                        msgs.at("server_hello")[0],
1✔
2137
                                        strip_message_header(vars.get_opt_bin("Message_ServerHello")));
2✔
2138
                     result.test_bin_eq("Encrypted Extensions",
2✔
2139
                                        msgs.at("encrypted_extensions")[0],
1✔
2140
                                        strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
2✔
2141
                     result.test_bin_eq("Certificate",
2✔
2142
                                        msgs.at("certificate")[0],
1✔
2143
                                        strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
2✔
2144
                     result.test_bin_eq("CertificateVerify",
2✔
2145
                                        msgs.at("certificate_verify")[0],
1✔
2146
                                        strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
2✔
2147
                     result.test_bin_eq("Finished",
2✔
2148
                                        msgs.at("finished")[0],
1✔
2149
                                        strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
2✔
2150

2151
                     result.test_bin_eq("Server's entire second flight",
1✔
2152
                                        ctx->pull_send_buffer(),
1✔
2153
                                        concat(vars.get_req_bin("Record_ServerHello"),
3✔
2154
                                               vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2155
                     result.test_is_true("Server could now send application data", ctx->server.is_active());
1✔
2156
                     result.test_is_true("handshake is not yet complete",
1✔
2157
                                         !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2158
                  }),
1✔
2159

2160
            CHECK("Receive Client Finished",
2161
                  [&](Test::Result& result) {
1✔
2162
                     result.require("ctx is available", ctx != nullptr);
1✔
2163
                     ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
1✔
2164

2165
                     ctx->check_callback_invocations(result,
2✔
2166
                                                     "client finished received",
2167
                                                     {"tls_inspect_handshake_msg_finished",
2168
                                                      "tls_current_timestamp",
2169
                                                      "tls_session_established",
2170
                                                      "tls_session_activated"});
2171

2172
                     result.test_is_true("TLS handshake finished", ctx->server.is_active());
1✔
2173
                     result.test_is_true("handshake is complete", ctx->server.is_handshake_complete());
1✔
2174
                  }),
1✔
2175

2176
            CHECK("Receive Client close_notify",
2177
                  [&](Test::Result& result) {
1✔
2178
                     result.require("ctx is available", ctx != nullptr);
1✔
2179
                     ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
1✔
2180

2181
                     ctx->check_callback_invocations(
2✔
2182
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2183

2184
                     result.test_is_true("connection is not yet closed", !ctx->server.is_closed());
1✔
2185
                     result.test_is_true("connection is still active", ctx->server.is_active());
1✔
2186
                     result.test_is_true("handshake is still complete", ctx->server.is_handshake_complete());
1✔
2187
                  }),
1✔
2188

2189
            CHECK("Expect Server close_notify",
2190
                  [&](Test::Result& result) {
1✔
2191
                     result.require("ctx is available", ctx != nullptr);
1✔
2192
                     ctx->server.close();
1✔
2193

2194
                     result.test_is_true("connection is now inactive", !ctx->server.is_active());
1✔
2195
                     result.test_is_true("connection is now closed", ctx->server.is_closed());
1✔
2196
                     result.test_is_true("handshake is still complete", ctx->server.is_handshake_complete());
1✔
2197
                     result.test_bin_eq("Server's close notify",
1✔
2198
                                        ctx->pull_send_buffer(),
1✔
2199
                                        vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2200
                  }),
1✔
2201

2202
         };
8✔
2203
      }
2✔
2204

2205
      std::vector<Test::Result> client_authentication(const VarMap& vars) override {
1✔
2206
         auto rng = std::make_unique<Fixed_Output_RNG>("");
1✔
2207

2208
         // 32 - for server hello random
2209
         // 32 - for KeyShare (eph. x25519 pair)
2210
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
1✔
2211

2212
         std::unique_ptr<Server_Context> ctx;
1✔
2213

2214
         return {
1✔
2215
            CHECK("Receive Client Hello",
2216
                  [&](Test::Result& result) {
1✔
2217
                     ctx = std::make_unique<Server_Context>(
1✔
2218
                        std::move(rng),
2219
                        std::make_shared<RFC8448_Text_Policy>("rfc8448_client_auth_server"),
2✔
2220
                        vars.get_req_u64("CurrentTimestamp"),
1✔
2221
                        sort_rfc8448_extensions,
2222
                        make_mock_signatures(vars),
1✔
2223
                        true /* use alternative certificate */);
2✔
2224
                     result.test_is_true("server not closed", !ctx->server.is_closed());
1✔
2225

2226
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
1✔
2227

2228
                     ctx->check_callback_invocations(result,
2✔
2229
                                                     "client hello received",
2230
                                                     {"tls_emit_data",
2231
                                                      "tls_examine_extensions_client_hello",
2232
                                                      "tls_modify_extensions_server_hello",
2233
                                                      "tls_modify_extensions_encrypted_extensions",
2234
                                                      "tls_modify_extensions_certificate_request",
2235
                                                      "tls_modify_extensions_certificate",
2236
                                                      "tls_sign_message",
2237
                                                      "tls_generate_ephemeral_key",
2238
                                                      "tls_ephemeral_key_agreement",
2239
                                                      "tls_inspect_handshake_msg_client_hello",
2240
                                                      "tls_inspect_handshake_msg_server_hello",
2241
                                                      "tls_inspect_handshake_msg_encrypted_extensions",
2242
                                                      "tls_inspect_handshake_msg_certificate_request",
2243
                                                      "tls_inspect_handshake_msg_certificate",
2244
                                                      "tls_inspect_handshake_msg_certificate_verify",
2245
                                                      "tls_inspect_handshake_msg_finished"});
2246
                  }),
1✔
2247

2248
            CHECK("Verify server's generated handshake messages",
2249
                  [&](Test::Result& result) {
1✔
2250
                     result.require("ctx is available", ctx != nullptr);
1✔
2251
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
2252

2253
                     result.test_bin_eq("Server Hello",
2✔
2254
                                        msgs.at("server_hello")[0],
1✔
2255
                                        strip_message_header(vars.get_opt_bin("Message_ServerHello")));
2✔
2256
                     result.test_bin_eq("Encrypted Extensions",
2✔
2257
                                        msgs.at("encrypted_extensions")[0],
1✔
2258
                                        strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
2✔
2259
                     result.test_bin_eq("Certificate Request",
2✔
2260
                                        msgs.at("certificate_request")[0],
1✔
2261
                                        strip_message_header(vars.get_opt_bin("Message_CertificateRequest")));
2✔
2262
                     result.test_bin_eq("Certificate",
2✔
2263
                                        msgs.at("certificate")[0],
1✔
2264
                                        strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
2✔
2265
                     result.test_bin_eq("CertificateVerify",
2✔
2266
                                        msgs.at("certificate_verify")[0],
1✔
2267
                                        strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
2✔
2268
                     result.test_bin_eq("Finished",
2✔
2269
                                        msgs.at("finished")[0],
1✔
2270
                                        strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
2✔
2271

2272
                     result.test_bin_eq("Server's entire first flight",
1✔
2273
                                        ctx->pull_send_buffer(),
1✔
2274
                                        concat(vars.get_req_bin("Record_ServerHello"),
3✔
2275
                                               vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2276

2277
                     result.test_is_true("Not yet aware of client's cert chain", ctx->server.peer_cert_chain().empty());
1✔
2278
                     result.test_is_true("Server could now send application data", ctx->server.is_active());
1✔
2279
                     result.test_is_true("handshake is not yet complete",
1✔
2280
                                         !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2281
                  }),
1✔
2282

2283
            CHECK("Receive Client's second flight",
2284
                  [&](Test::Result& result) {
1✔
2285
                     result.require("ctx is available", ctx != nullptr);
1✔
2286
                     // This encrypted message contains the following messages:
2287
                     // * client's Certificate message
2288
                     // * client's Certificate_Verify message
2289
                     // * client's Finished message
2290
                     ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
1✔
2291

2292
                     ctx->check_callback_invocations(result,
2✔
2293
                                                     "client finished received",
2294
                                                     {"tls_inspect_handshake_msg_certificate",
2295
                                                      "tls_inspect_handshake_msg_certificate_verify",
2296
                                                      "tls_inspect_handshake_msg_finished",
2297
                                                      "tls_examine_extensions_certificate",
2298
                                                      "tls_verify_cert_chain",
2299
                                                      "tls_verify_message",
2300
                                                      "tls_current_timestamp",
2301
                                                      "tls_session_established",
2302
                                                      "tls_session_activated"});
2303

2304
                     const auto cert_chain = ctx->server.peer_cert_chain();
1✔
2305
                     result.test_is_true("Received client's cert chain",
1✔
2306
                                         !cert_chain.empty() && cert_chain.front() == client_certificate());
2✔
2307

2308
                     result.test_is_true("TLS handshake finished", ctx->server.is_active());
1✔
2309
                     result.test_is_true("handshake is complete", ctx->server.is_handshake_complete());
1✔
2310
                  }),
1✔
2311

2312
            CHECK("Receive Client close_notify",
2313
                  [&](Test::Result& result) {
1✔
2314
                     result.require("ctx is available", ctx != nullptr);
1✔
2315
                     ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
1✔
2316

2317
                     ctx->check_callback_invocations(
2✔
2318
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2319

2320
                     result.test_is_true("connection is not yet closed", !ctx->server.is_closed());
1✔
2321
                     result.test_is_true("connection is still active", ctx->server.is_active());
1✔
2322
                     result.test_is_true("handshake is still complete", ctx->server.is_handshake_complete());
1✔
2323
                  }),
1✔
2324

2325
            CHECK("Expect Server close_notify",
2326
                  [&](Test::Result& result) {
1✔
2327
                     result.require("ctx is available", ctx != nullptr);
1✔
2328
                     ctx->server.close();
1✔
2329

2330
                     result.test_is_true("connection is now inactive", !ctx->server.is_active());
1✔
2331
                     result.test_is_true("connection is now closed", ctx->server.is_closed());
1✔
2332
                     result.test_is_true("handshake is still complete", ctx->server.is_handshake_complete());
1✔
2333
                     result.test_bin_eq("Server's close notify",
1✔
2334
                                        ctx->pull_send_buffer(),
1✔
2335
                                        vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2336
                  }),
1✔
2337

2338
         };
6✔
2339
      }
2✔
2340

2341
      std::vector<Test::Result> middlebox_compatibility(const VarMap& vars) override {
1✔
2342
         auto rng = std::make_unique<Fixed_Output_RNG>("");
1✔
2343

2344
         // 32 - for server hello random
2345
         // 32 - for KeyShare (eph. x25519 pair)
2346
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
1✔
2347

2348
         std::unique_ptr<Server_Context> ctx;
1✔
2349

2350
         return {
1✔
2351
            CHECK("Receive Client Hello",
2352
                  [&](Test::Result& result) {
1✔
2353
                     ctx =
1✔
2354
                        std::make_unique<Server_Context>(std::move(rng),
1✔
2355
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_compat_server"),
2✔
2356
                                                         vars.get_req_u64("CurrentTimestamp"),
1✔
2357
                                                         sort_rfc8448_extensions,
2358
                                                         make_mock_signatures(vars));
3✔
2359
                     result.test_is_true("server not closed", !ctx->server.is_closed());
1✔
2360

2361
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
1✔
2362

2363
                     ctx->check_callback_invocations(result,
2✔
2364
                                                     "client hello received",
2365
                                                     {"tls_emit_data",
2366
                                                      "tls_examine_extensions_client_hello",
2367
                                                      "tls_modify_extensions_server_hello",
2368
                                                      "tls_modify_extensions_encrypted_extensions",
2369
                                                      "tls_modify_extensions_certificate",
2370
                                                      "tls_sign_message",
2371
                                                      "tls_generate_ephemeral_key",
2372
                                                      "tls_ephemeral_key_agreement",
2373
                                                      "tls_inspect_handshake_msg_client_hello",
2374
                                                      "tls_inspect_handshake_msg_server_hello",
2375
                                                      "tls_inspect_handshake_msg_encrypted_extensions",
2376
                                                      "tls_inspect_handshake_msg_certificate",
2377
                                                      "tls_inspect_handshake_msg_certificate_verify",
2378
                                                      "tls_inspect_handshake_msg_finished"});
2379
                  }),
1✔
2380

2381
            CHECK("Verify server's generated handshake messages",
2382
                  [&](Test::Result& result) {
1✔
2383
                     result.require("ctx is available", ctx != nullptr);
1✔
2384
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
2385

2386
                     result.test_bin_eq("Server Hello",
2✔
2387
                                        msgs.at("server_hello")[0],
1✔
2388
                                        strip_message_header(vars.get_opt_bin("Message_ServerHello")));
2✔
2389
                     result.test_bin_eq("Encrypted Extensions",
2✔
2390
                                        msgs.at("encrypted_extensions")[0],
1✔
2391
                                        strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
2✔
2392
                     result.test_bin_eq("Certificate",
2✔
2393
                                        msgs.at("certificate")[0],
1✔
2394
                                        strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
2✔
2395
                     result.test_bin_eq("CertificateVerify",
2✔
2396
                                        msgs.at("certificate_verify")[0],
1✔
2397
                                        strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
2✔
2398
                     result.test_bin_eq("Finished",
2✔
2399
                                        msgs.at("finished")[0],
1✔
2400
                                        strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
2✔
2401

2402
                     // Those records contain the required Change Cipher Spec message the server must produce for compatibility mode compliance
2403
                     result.test_bin_eq("Server's entire first flight",
1✔
2404
                                        ctx->pull_send_buffer(),
1✔
2405
                                        concat(vars.get_req_bin("Record_ServerHello"),
3✔
2406
                                               vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2407

2408
                     result.test_is_true("Server could now send application data", ctx->server.is_active());
1✔
2409
                     result.test_is_true("handshake is not yet complete",
1✔
2410
                                         !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2411
                  }),
1✔
2412

2413
            CHECK("Receive Client Finished",
2414
                  [&](Test::Result& result) {
1✔
2415
                     result.require("ctx is available", ctx != nullptr);
1✔
2416
                     ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
1✔
2417

2418
                     ctx->check_callback_invocations(result,
2✔
2419
                                                     "client finished received",
2420
                                                     {"tls_inspect_handshake_msg_finished",
2421
                                                      "tls_current_timestamp",
2422
                                                      "tls_session_established",
2423
                                                      "tls_session_activated"});
2424

2425
                     result.test_is_true("TLS handshake fully finished", ctx->server.is_active());
1✔
2426
                     result.test_is_true("handshake is complete", ctx->server.is_handshake_complete());
1✔
2427
                  }),
1✔
2428

2429
            CHECK("Receive Client close_notify",
2430
                  [&](Test::Result& result) {
1✔
2431
                     result.require("ctx is available", ctx != nullptr);
1✔
2432
                     ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
1✔
2433

2434
                     ctx->check_callback_invocations(
2✔
2435
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2436

2437
                     result.test_is_true("connection is not yet closed", !ctx->server.is_closed());
1✔
2438
                     result.test_is_true("connection is still active", ctx->server.is_active());
1✔
2439
                     result.test_is_true("handshake is still complete", ctx->server.is_handshake_complete());
1✔
2440
                  }),
1✔
2441

2442
            CHECK("Expect Server close_notify",
2443
                  [&](Test::Result& result) {
1✔
2444
                     result.require("ctx is available", ctx != nullptr);
1✔
2445
                     ctx->server.close();
1✔
2446

2447
                     result.test_is_true("connection is now inactive", !ctx->server.is_active());
1✔
2448
                     result.test_is_true("connection is now closed", ctx->server.is_closed());
1✔
2449
                     result.test_is_true("handshake is still complete", ctx->server.is_handshake_complete());
1✔
2450
                     result.test_bin_eq("Server's close notify",
1✔
2451
                                        ctx->pull_send_buffer(),
1✔
2452
                                        vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2453
                  }),
1✔
2454

2455
         };
6✔
2456
      }
2✔
2457

2458
      std::vector<Test::Result> externally_provided_psk_with_ephemeral_key(const VarMap& vars) override {
1✔
2459
         auto rng = std::make_unique<Fixed_Output_RNG>("");
1✔
2460

2461
         // 32 - for server hello random
2462
         // 32 - for KeyShare (eph. x25519 key pair)
2463
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
1✔
2464

2465
         std::unique_ptr<Server_Context> ctx;
1✔
2466

2467
         return {
1✔
2468
            CHECK("Send Client Hello",
2469
                  [&](Test::Result& result) {
1✔
2470
                     auto sort_our_extensions = [&](Botan::TLS::Extensions& exts,
3✔
2471
                                                    Botan::TLS::Connection_Side /* side */,
2472
                                                    Botan::TLS::Handshake_Type type) {
2473
                        // This is the order of extensions when we first introduced the PSK
2474
                        // implementation and generated the transcript. To stay compatible
2475
                        // with the now hard-coded transcript, we pin the extension order.
2476
                        if(type == Botan::TLS::Handshake_Type::EncryptedExtensions) {
2✔
2477
                           sort_extensions(exts,
2✔
2478
                                           {
2479
                                              Botan::TLS::Extension_Code::SupportedGroups,
2480
                                              Botan::TLS::Extension_Code::RecordSizeLimit,
2481
                                              Botan::TLS::Extension_Code::ServerNameIndication,
2482
                                           });
2483
                        } else if(type == Botan::TLS::Handshake_Type::ServerHello) {
1✔
2484
                           sort_extensions(exts,
2✔
2485
                                           {
2486
                                              Botan::TLS::Extension_Code::SupportedVersions,
2487
                                              Botan::TLS::Extension_Code::KeyShare,
2488
                                              Botan::TLS::Extension_Code::PresharedKey,
2489
                                           });
2490
                        }
2491
                     };
2✔
2492

2493
                     ctx = std::make_unique<Server_Context>(
1✔
2494
                        std::move(rng),
2495
                        std::make_shared<RFC8448_Text_Policy>("rfc8448_psk_dhe", false /* no rfc8448 */),
2✔
2496
                        vars.get_req_u64("CurrentTimestamp"),
1✔
2497
                        sort_our_extensions,
2498
                        make_mock_signatures(vars),
1✔
2499
                        false,
1✔
2500
                        std::nullopt,
2501
                        ExternalPSK(vars.get_req_str("PskIdentity"),
2✔
2502
                                    vars.get_req_str("PskPRF"),
2✔
2503
                                    lock(vars.get_req_bin("PskSecret"))));
4✔
2504
                     result.test_is_true("server not closed", !ctx->server.is_closed());
1✔
2505

2506
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
1✔
2507

2508
                     ctx->check_callback_invocations(result,
2✔
2509
                                                     "client hello received",
2510
                                                     {"tls_emit_data",
2511
                                                      "tls_examine_extensions_client_hello",
2512
                                                      "tls_modify_extensions_server_hello",
2513
                                                      "tls_modify_extensions_encrypted_extensions",
2514
                                                      "tls_generate_ephemeral_key",
2515
                                                      "tls_ephemeral_key_agreement",
2516
                                                      "tls_inspect_handshake_msg_client_hello",
2517
                                                      "tls_inspect_handshake_msg_server_hello",
2518
                                                      "tls_inspect_handshake_msg_encrypted_extensions",
2519
                                                      "tls_inspect_handshake_msg_finished"});
2520
                  }),
1✔
2521

2522
            CHECK("Verify generated messages in server's first flight",
2523
                  [&](Test::Result& result) {
1✔
2524
                     result.require("ctx is available", ctx != nullptr);
1✔
2525
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
2526

2527
                     result.test_bin_eq("Server Hello",
2✔
2528
                                        msgs.at("server_hello")[0],
1✔
2529
                                        strip_message_header(vars.get_opt_bin("Message_ServerHello")));
2✔
2530
                     result.test_bin_eq("Encrypted Extensions",
2✔
2531
                                        msgs.at("encrypted_extensions")[0],
1✔
2532
                                        strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
2✔
2533
                     result.test_bin_eq("Server Finished",
2✔
2534
                                        msgs.at("finished")[0],
1✔
2535
                                        strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
2✔
2536

2537
                     result.test_bin_eq("Server's entire first flight",
1✔
2538
                                        ctx->pull_send_buffer(),
1✔
2539
                                        concat(vars.get_req_bin("Record_ServerHello"),
3✔
2540
                                               vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2541

2542
                     result.test_is_true("Server can now send application data", ctx->server.is_active());
1✔
2543
                     result.test_is_true("handshake is not yet complete",
1✔
2544
                                         !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2545
                  }),
1✔
2546

2547
            CHECK("Send Client Finished",
2548
                  [&](Test::Result& result) {
1✔
2549
                     result.require("ctx is available", ctx != nullptr);
1✔
2550
                     ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
1✔
2551
                     result.require("PSK negotiated",
1✔
2552
                                    ctx->psk_identity_negotiated() == vars.get_req_str("PskIdentity"));
2✔
2553

2554
                     ctx->check_callback_invocations(result,
2✔
2555
                                                     "client finished received",
2556
                                                     {"tls_inspect_handshake_msg_finished",
2557
                                                      "tls_current_timestamp",
2558
                                                      "tls_session_established",
2559
                                                      "tls_session_activated"});
2560
                  }),
1✔
2561

2562
            CHECK("Exchange Application Data",
2563
                  [&](Test::Result& result) {
1✔
2564
                     result.require("ctx is available", ctx != nullptr);
1✔
2565
                     ctx->server.received_data(vars.get_req_bin("Record_Client_AppData"));
1✔
2566
                     ctx->check_callback_invocations(result, "application data received", {"tls_record_received"});
2✔
2567

2568
                     const auto rcvd = ctx->pull_receive_buffer();
1✔
2569
                     result.test_bin_eq("decrypted application traffic", rcvd, vars.get_req_bin("Client_AppData"));
1✔
2570
                     result.test_u64_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
1✔
2571

2572
                     ctx->send(vars.get_req_bin("Server_AppData"));
2✔
2573
                     ctx->check_callback_invocations(result, "application data sent", {"tls_emit_data"});
2✔
2574
                     result.test_bin_eq("correct server application data",
1✔
2575
                                        ctx->pull_send_buffer(),
1✔
2576
                                        vars.get_req_bin("Record_Server_AppData"));
2✔
2577
                  }),
1✔
2578

2579
            CHECK("Terminate Connection",
2580
                  [&](Test::Result& result) {
1✔
2581
                     result.require("ctx is available", ctx != nullptr);
1✔
2582
                     ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
1✔
2583

2584
                     ctx->check_callback_invocations(
2✔
2585
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2586

2587
                     result.test_is_true("connection is not yet closed", !ctx->server.is_closed());
1✔
2588
                     result.test_is_true("connection is still active", ctx->server.is_active());
1✔
2589
                     result.test_is_true("handshake is still complete", ctx->server.is_handshake_complete());
1✔
2590

2591
                     ctx->server.close();
1✔
2592

2593
                     result.test_is_true("connection is now inactive", !ctx->server.is_active());
1✔
2594
                     result.test_is_true("connection is now closed", ctx->server.is_closed());
1✔
2595
                     result.test_is_true("handshake is still complete", ctx->server.is_handshake_complete());
1✔
2596
                     result.test_bin_eq("Server's close notify",
1✔
2597
                                        ctx->pull_send_buffer(),
1✔
2598
                                        vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2599
                  }),
1✔
2600
         };
6✔
2601
      }
2✔
2602

2603
      std::vector<Test::Result> raw_public_key_with_client_authentication(const VarMap& vars) override {
1✔
2604
         auto rng = std::make_unique<Fixed_Output_RNG>("");
1✔
2605

2606
         // 32 - for server hello random
2607
         // 32 - for KeyShare (eph. x25519 key pair)
2608
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
1✔
2609

2610
         auto sort_our_extensions =
1✔
2611
            [&](Botan::TLS::Extensions& exts, Botan::TLS::Connection_Side /* side */, Botan::TLS::Handshake_Type type) {
4✔
2612
               // This is the order of extensions when we first introduced the raw
2613
               // public key authentication implementation and generated the transcript.
2614
               // To stay compatible with the now hard-coded transcript, we pin the
2615
               // extension order.
2616
               if(type == Botan::TLS::Handshake_Type::EncryptedExtensions) {
4✔
2617
                  sort_extensions(exts,
2✔
2618
                                  {
2619
                                     Botan::TLS::Extension_Code::ClientCertificateType,
2620
                                     Botan::TLS::Extension_Code::ServerCertificateType,
2621
                                     Botan::TLS::Extension_Code::SupportedGroups,
2622
                                     Botan::TLS::Extension_Code::RecordSizeLimit,
2623
                                     Botan::TLS::Extension_Code::ServerNameIndication,
2624
                                  });
2625
               } else if(type == Botan::TLS::Handshake_Type::ServerHello) {
3✔
2626
                  sort_extensions(exts,
2✔
2627
                                  {
2628
                                     Botan::TLS::Extension_Code::KeyShare,
2629
                                     Botan::TLS::Extension_Code::SupportedVersions,
2630
                                  });
2631
               }
2632
            };
4✔
2633

2634
         std::unique_ptr<Server_Context> ctx;
1✔
2635

2636
         return {
1✔
2637
            CHECK("Receive Client Hello",
2638
                  [&](Test::Result& result) {
1✔
2639
                     ctx = std::make_unique<Server_Context>(std::move(rng),
1✔
2640
                                                            std::make_shared<RFC8448_Text_Policy>("rfc8448_rawpubkey"),
2✔
2641
                                                            vars.get_req_u64("CurrentTimestamp"),
1✔
2642
                                                            sort_our_extensions,
2643
                                                            make_mock_signatures(vars));
3✔
2644
                     result.test_is_true("server not closed", !ctx->server.is_closed());
1✔
2645

2646
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
1✔
2647

2648
                     ctx->check_callback_invocations(result,
2✔
2649
                                                     "client hello received",
2650
                                                     {"tls_emit_data",
2651
                                                      "tls_examine_extensions_client_hello",
2652
                                                      "tls_modify_extensions_server_hello",
2653
                                                      "tls_modify_extensions_encrypted_extensions",
2654
                                                      "tls_modify_extensions_certificate_request",
2655
                                                      "tls_modify_extensions_certificate",
2656
                                                      "tls_sign_message",
2657
                                                      "tls_generate_ephemeral_key",
2658
                                                      "tls_ephemeral_key_agreement",
2659
                                                      "tls_inspect_handshake_msg_client_hello",
2660
                                                      "tls_inspect_handshake_msg_server_hello",
2661
                                                      "tls_inspect_handshake_msg_encrypted_extensions",
2662
                                                      "tls_inspect_handshake_msg_certificate_request",
2663
                                                      "tls_inspect_handshake_msg_certificate",
2664
                                                      "tls_inspect_handshake_msg_certificate_verify",
2665
                                                      "tls_inspect_handshake_msg_finished"});
2666
                  }),
1✔
2667

2668
            CHECK("Verify server's generated handshake messages",
2669
                  [&](Test::Result& result) {
1✔
2670
                     result.require("ctx is available", ctx != nullptr);
1✔
2671
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
2672

2673
                     result.test_bin_eq("Server Hello",
2✔
2674
                                        msgs.at("server_hello")[0],
1✔
2675
                                        strip_message_header(vars.get_opt_bin("Message_ServerHello")));
2✔
2676
                     result.test_bin_eq("Encrypted Extensions",
2✔
2677
                                        msgs.at("encrypted_extensions")[0],
1✔
2678
                                        strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
2✔
2679
                     result.test_bin_eq("Certificate Request",
2✔
2680
                                        msgs.at("certificate_request")[0],
1✔
2681
                                        strip_message_header(vars.get_opt_bin("Message_CertificateRequest")));
2✔
2682
                     result.test_bin_eq("Certificate",
2✔
2683
                                        msgs.at("certificate")[0],
1✔
2684
                                        strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
2✔
2685
                     result.test_bin_eq("CertificateVerify",
2✔
2686
                                        msgs.at("certificate_verify")[0],
1✔
2687
                                        strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
2✔
2688
                     result.test_bin_eq("Finished",
2✔
2689
                                        msgs.at("finished")[0],
1✔
2690
                                        strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
2✔
2691

2692
                     result.test_bin_eq("Server's entire first flight",
1✔
2693
                                        ctx->pull_send_buffer(),
1✔
2694
                                        concat(vars.get_req_bin("Record_ServerHello"),
3✔
2695
                                               vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2696

2697
                     result.test_is_true("Not yet aware of client's cert chain", ctx->server.peer_cert_chain().empty());
1✔
2698
                     result.test_is_true("Server could now send application data", ctx->server.is_active());
1✔
2699
                     result.test_is_true("handshake is not yet complete",
1✔
2700
                                         !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2701
                  }),
1✔
2702

2703
            CHECK("Receive Client's second flight",
2704
                  [&](Test::Result& result) {
1✔
2705
                     result.require("ctx is available", ctx != nullptr);
1✔
2706
                     // This encrypted message contains the following messages:
2707
                     // * client's Certificate message
2708
                     // * client's Certificate_Verify message
2709
                     // * client's Finished message
2710
                     ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
1✔
2711

2712
                     ctx->check_callback_invocations(result,
2✔
2713
                                                     "client finished received",
2714
                                                     {"tls_inspect_handshake_msg_certificate",
2715
                                                      "tls_inspect_handshake_msg_certificate_verify",
2716
                                                      "tls_inspect_handshake_msg_finished",
2717
                                                      "tls_examine_extensions_certificate",
2718
                                                      "tls_verify_raw_public_key",
2719
                                                      "tls_verify_message",
2720
                                                      "tls_current_timestamp",
2721
                                                      "tls_session_established",
2722
                                                      "tls_session_activated"});
2723

2724
                     const auto raw_pk = ctx->server.peer_raw_public_key();
1✔
2725
                     result.test_is_true(
1✔
2726
                        "Received client's raw public key",
2727
                        raw_pk && raw_pk->fingerprint_public() == client_raw_public_key_pair()->fingerprint_public());
5✔
2728

2729
                     result.test_is_true("TLS handshake finished", ctx->server.is_active());
1✔
2730
                     result.test_is_true("handshake is complete", ctx->server.is_handshake_complete());
1✔
2731
                  }),
1✔
2732

2733
            CHECK("Receive Client close_notify",
2734
                  [&](Test::Result& result) {
1✔
2735
                     result.require("ctx is available", ctx != nullptr);
1✔
2736
                     ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
1✔
2737

2738
                     ctx->check_callback_invocations(
2✔
2739
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2740

2741
                     result.test_is_true("connection is not yet closed", !ctx->server.is_closed());
1✔
2742
                     result.test_is_true("connection is still active", ctx->server.is_active());
1✔
2743
                     result.test_is_true("handshake is still complete", ctx->server.is_handshake_complete());
1✔
2744
                  }),
1✔
2745

2746
            CHECK("Expect Server close_notify",
2747
                  [&](Test::Result& result) {
1✔
2748
                     result.require("ctx is available", ctx != nullptr);
1✔
2749
                     ctx->server.close();
1✔
2750

2751
                     result.test_is_true("connection is now inactive", !ctx->server.is_active());
1✔
2752
                     result.test_is_true("connection is now closed", ctx->server.is_closed());
1✔
2753
                     result.test_is_true("handshake is still complete", ctx->server.is_handshake_complete());
1✔
2754
                     result.test_bin_eq("Server's close notify",
1✔
2755
                                        ctx->pull_send_buffer(),
1✔
2756
                                        vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2757
                  }),
1✔
2758
         };
6✔
2759
      }
2✔
2760
};
2761

2762
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_client", Test_TLS_RFC8448_Client);
2763
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_server", Test_TLS_RFC8448_Server);
2764

2765
#endif
2766

2767
}  // namespace Botan_Tests
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