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

randombit / botan / 11087146043

28 Sep 2024 09:28PM UTC coverage: 92.003% (+0.7%) from 91.274%
11087146043

push

github

web-flow
Create terraform.yml

82959 of 90170 relevant lines covered (92.0%)

9376319.11 hits per line

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

97.41
/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_13) && defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) && defined(BOTAN_HAS_AEAD_GCM) &&          \
17
   defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_X25519) && defined(BOTAN_HAS_SHA2_32) && defined(BOTAN_HAS_SHA2_64) && \
18
   defined(BOTAN_HAS_ECDSA)
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/ecdsa.h>
29
   #include <botan/hash.h>
30
   #include <botan/pk_algs.h>
31
   #include <botan/pkcs8.h>
32
   #include <botan/rsa.h>
33
   #include <botan/tls.h>
34
   #include <botan/tls_extensions.h>
35
   #include <botan/tls_messages.h>
36
   #include <botan/x509_key.h>
37
   #include <botan/internal/fmt.h>
38
   #include <botan/internal/stl_util.h>
39
#endif
40

41
namespace Botan_Tests {
42

43
#if defined(BOTAN_CAN_RUN_TEST_TLS_RFC8448)
44

45
namespace {
46

47
void add_entropy(Botan_Tests::Fixed_Output_RNG& rng, const std::vector<uint8_t>& bin) {
14✔
48
   rng.add_entropy(bin.data(), bin.size());
28✔
49
}
50

51
Botan::X509_Certificate server_certificate() {
4✔
52
   // self-signed certificate with an RSA1024 public key valid until:
53
   //   Jul 30 01:23:59 2026 GMT
54
   Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/server_certificate.pem"));
8✔
55
   return Botan::X509_Certificate(in);
4✔
56
}
4✔
57

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

68
Botan::X509_Certificate client_certificate() {
2✔
69
   // self-signed certificate with an RSA1024 public key valid until:
70
   //   Jul 30 01:23:59 2026 GMT
71
   Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/client_certificate.pem"));
4✔
72
   return Botan::X509_Certificate(in);
2✔
73
}
2✔
74

75
std::unique_ptr<Botan::Private_Key> client_raw_public_key_pair() {
4✔
76
   // P-256 private key (independently generated)
77
   Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/client_raw_public_keypair.pem"));
8✔
78
   return Botan::PKCS8::load_key(in);
4✔
79
}
4✔
80

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

87
/**
88
* Simple version of the Padding extension (RFC 7685) to reproduce the
89
* 2nd Client_Hello in RFC8448 Section 5 (HelloRetryRequest)
90
*/
91
class Padding final : public Botan::TLS::Extension {
92
   public:
93
      static Botan::TLS::Extension_Code static_type() { return Botan::TLS::Extension_Code(21); }
94

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

97
      explicit Padding(const size_t padding_bytes) : m_padding_bytes(padding_bytes) {}
2✔
98

99
      std::vector<uint8_t> serialize(Botan::TLS::Connection_Side) const override {
5✔
100
         return std::vector<uint8_t>(m_padding_bytes, 0x00);
5✔
101
      }
102

103
      bool empty() const override { return m_padding_bytes == 0; }
5✔
104

105
   private:
106
      size_t m_padding_bytes;
107
};
108

109
using namespace Botan;
110
using namespace Botan::TLS;
111

112
std::chrono::system_clock::time_point from_milliseconds_since_epoch(uint64_t msecs) {
14✔
113
   const int64_t secs_since_epoch = msecs / 1000;
14✔
114
   const uint32_t additional_millis = msecs % 1000;
14✔
115

116
   BOTAN_ASSERT_NOMSG(secs_since_epoch <= std::numeric_limits<time_t>::max());
14✔
117
   return std::chrono::system_clock::from_time_t(static_cast<time_t>(secs_since_epoch)) +
14✔
118
          std::chrono::milliseconds(additional_millis);
14✔
119
}
120

121
using Modify_Exts_Fn =
122
   std::function<void(Botan::TLS::Extensions&, Botan::TLS::Connection_Side, Botan::TLS::Handshake_Type)>;
123

124
/**
125
 * We cannot actually reproduce the signatures stated in RFC 8448 as their
126
 * signature scheme is probabilistic and we're lacking the correct RNG
127
 * input. Hence, signatures are know beforehand and just reproduced by the
128
 * TLS callback when requested.
129
 */
130
struct MockSignature {
15✔
131
      std::vector<uint8_t> message_to_sign;
132
      std::vector<uint8_t> signature_to_produce;
133
};
134

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

151
      void tls_emit_data(std::span<const uint8_t> data) override {
47✔
152
         count_callback_invocation("tls_emit_data");
47✔
153
         send_buffer.insert(send_buffer.end(), data.begin(), data.end());
47✔
154
      }
47✔
155

156
      void tls_record_received(uint64_t seq_no, std::span<const uint8_t> data) override {
4✔
157
         count_callback_invocation("tls_record_received");
4✔
158
         received_seq_no = seq_no;
4✔
159
         receive_buffer.insert(receive_buffer.end(), data.begin(), data.end());
4✔
160
      }
4✔
161

162
      void tls_alert(Botan::TLS::Alert alert) override {
12✔
163
         count_callback_invocation("tls_alert");
12✔
164
         BOTAN_UNUSED(alert);
12✔
165
         // handle a tls alert received from the tls server
166
      }
12✔
167

168
      bool tls_peer_closed_connection() override {
12✔
169
         count_callback_invocation("tls_peer_closed_connection");
12✔
170
         // we want to handle the closure ourselves
171
         return false;
12✔
172
      }
173

174
      void tls_session_established(const Botan::TLS::Session_Summary& summary) override {
12✔
175
         if(summary.psk_used()) {
12✔
176
            negotiated_psk_identity = summary.external_psk_identity().value();
2✔
177
         }
178
         count_callback_invocation("tls_session_established");
12✔
179
      }
12✔
180

181
      void tls_session_activated() override {
12✔
182
         count_callback_invocation("tls_session_activated");
12✔
183
         session_activated_called = true;
12✔
184
      }
12✔
185

186
      bool tls_should_persist_resumption_information(const Session&) override {
2✔
187
         count_callback_invocation("tls_should_persist_resumption_information");
2✔
188
         return true;  // should always store the session
2✔
189
      }
190

191
      void tls_verify_cert_chain(const std::vector<Botan::X509_Certificate>& cert_chain,
5✔
192
                                 const std::vector<std::optional<Botan::OCSP::Response>>&,
193
                                 const std::vector<Botan::Certificate_Store*>&,
194
                                 Botan::Usage_Type,
195
                                 std::string_view,
196
                                 const Botan::TLS::Policy&) override {
197
         count_callback_invocation("tls_verify_cert_chain");
5✔
198
         certificate_chain = cert_chain;
5✔
199
      }
5✔
200

201
      void tls_verify_raw_public_key(const Public_Key& raw_pk,
2✔
202
                                     Usage_Type,
203
                                     std::string_view,
204
                                     const TLS::Policy&) override {
205
         count_callback_invocation("tls_verify_raw_public_key");
2✔
206
         // TODO: is there a better way to copy a generic public key?
207
         raw_public_key = Botan::X509::load_key(raw_pk.subject_public_key());
2✔
208
      }
2✔
209

210
      std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const override {
×
211
         count_callback_invocation("tls_verify_cert_chain");
×
212
         return std::chrono::milliseconds(0);
×
213
      }
214

215
      std::vector<uint8_t> tls_provide_cert_status(const std::vector<X509_Certificate>& chain,
×
216
                                                   const Certificate_Status_Request& csr) override {
217
         count_callback_invocation("tls_provide_cert_status");
×
218
         return Callbacks::tls_provide_cert_status(chain, csr);
×
219
      }
220

221
      std::vector<uint8_t> tls_sign_message(const Private_Key& key,
7✔
222
                                            RandomNumberGenerator& rng,
223
                                            std::string_view padding,
224
                                            Signature_Format format,
225
                                            const std::vector<uint8_t>& msg) override {
226
         BOTAN_UNUSED(key, rng);
7✔
227
         count_callback_invocation("tls_sign_message");
7✔
228

229
         if(key.algo_name() == "RSA") {
7✔
230
            if(format != Signature_Format::Standard) {
4✔
231
               throw Test_Error("TLS implementation selected unexpected signature format for RSA");
×
232
            }
233

234
            if(padding != "PSSR(SHA-256,MGF1,32)") {
8✔
235
               throw Test_Error("TLS implementation selected unexpected padding for RSA: " + std::string(padding));
×
236
            }
237
         } else if(key.algo_name() == "ECDSA") {
3✔
238
            if(format != Signature_Format::DerSequence) {
3✔
239
               throw Test_Error("TLS implementation selected unexpected signature format for ECDSA");
×
240
            }
241

242
            if(padding != "SHA-256") {
6✔
243
               throw Test_Error("TLS implementation selected unexpected padding for ECDSA: " + std::string(padding));
×
244
            }
245
         } else {
246
            throw Test_Error("TLS implementation trying to sign with unexpected algorithm (" + key.algo_name() + ")");
×
247
         }
248

249
         for(const auto& mock : m_mock_signatures) {
9✔
250
            if(mock.message_to_sign == msg) {
9✔
251
               return mock.signature_to_produce;
7✔
252
            }
253
         }
254

255
         throw Test_Error("TLS implementation produced an unexpected message to be signed: " + Botan::hex_encode(msg));
×
256
      }
257

258
      bool tls_verify_message(const Public_Key& key,
7✔
259
                              std::string_view padding,
260
                              Signature_Format format,
261
                              const std::vector<uint8_t>& msg,
262
                              const std::vector<uint8_t>& sig) override {
263
         count_callback_invocation("tls_verify_message");
7✔
264
         return Callbacks::tls_verify_message(key, padding, format, msg, sig);
7✔
265
      }
266

267
      std::unique_ptr<PK_Key_Agreement_Key> tls_generate_ephemeral_key(
15✔
268
         const std::variant<TLS::Group_Params, DL_Group>& group, RandomNumberGenerator& rng) override {
269
         count_callback_invocation("tls_generate_ephemeral_key");
15✔
270
         return Callbacks::tls_generate_ephemeral_key(group, rng);
15✔
271
      }
272

273
      secure_vector<uint8_t> tls_ephemeral_key_agreement(const std::variant<TLS::Group_Params, DL_Group>& group,
13✔
274
                                                         const PK_Key_Agreement_Key& private_key,
275
                                                         const std::vector<uint8_t>& public_value,
276
                                                         RandomNumberGenerator& rng,
277
                                                         const Policy& policy) override {
278
         count_callback_invocation("tls_ephemeral_key_agreement");
13✔
279
         return Callbacks::tls_ephemeral_key_agreement(group, private_key, public_value, rng, policy);
13✔
280
      }
281

282
      void tls_inspect_handshake_msg(const Handshake_Message& message) override {
102✔
283
         count_callback_invocation("tls_inspect_handshake_msg_" + message.type_string());
204✔
284

285
         try {
102✔
286
            auto serialized_message = message.serialize();
102✔
287

288
            serialized_messages.try_emplace(message.type_string())
208✔
289
               .first->second.emplace_back(std::move(serialized_message));
102✔
290
         } catch(const Not_Implemented&) {
102✔
291
            // TODO: Once the server implementation is finished, this crutch
292
            //       can likely be removed, as all message types will have a
293
            //       serialization method with actual business logic. :o)
294
         }
×
295

296
         return Callbacks::tls_inspect_handshake_msg(message);
102✔
297
      }
298

299
      std::string tls_server_choose_app_protocol(const std::vector<std::string>& client_protos) override {
×
300
         count_callback_invocation("tls_server_choose_app_protocol");
×
301
         return Callbacks::tls_server_choose_app_protocol(client_protos);
×
302
      }
303

304
      void tls_modify_extensions(Botan::TLS::Extensions& exts,
31✔
305
                                 Botan::TLS::Connection_Side side,
306
                                 Botan::TLS::Handshake_Type which_message) override {
307
         count_callback_invocation(std::string("tls_modify_extensions_") + handshake_type_to_string(which_message));
62✔
308
         m_modify_exts(exts, side, which_message);
31✔
309
         Callbacks::tls_modify_extensions(exts, side, which_message);
31✔
310
      }
31✔
311

312
      void tls_examine_extensions(const Botan::TLS::Extensions& extn,
31✔
313
                                  Connection_Side which_side,
314
                                  Botan::TLS::Handshake_Type which_message) override {
315
         count_callback_invocation(std::string("tls_examine_extensions_") + handshake_type_to_string(which_message));
62✔
316
         return Callbacks::tls_examine_extensions(extn, which_side, which_message);
31✔
317
      }
318

319
      std::string tls_peer_network_identity() override {
×
320
         count_callback_invocation("tls_peer_network_identity");
×
321
         return Callbacks::tls_peer_network_identity();
×
322
      }
323

324
      std::chrono::system_clock::time_point tls_current_timestamp() override {
23✔
325
         count_callback_invocation("tls_current_timestamp");
23✔
326
         return m_timestamp;
23✔
327
      }
328

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

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

333
      uint64_t last_received_seq_no() const { return received_seq_no; }
4✔
334

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

337
      void reset_callback_invocation_counters() { m_callback_invocations.clear(); }
60✔
338

339
   private:
340
      void count_callback_invocation(const std::string& callback_name) const {
337✔
341
         if(!m_callback_invocations.contains(callback_name)) {
337✔
342
            m_callback_invocations[callback_name] = 0;
318✔
343
         }
344

345
         m_callback_invocations[callback_name]++;
337✔
346
      }
337✔
347

348
   public:
349
      bool session_activated_called;                           // NOLINT(*-non-private-member-variables-in-classes)
350
      std::vector<Botan::X509_Certificate> certificate_chain;  // NOLINT(*-non-private-member-variables-in-classes)
351
      std::unique_ptr<Botan::Public_Key> raw_public_key;       // NOLINT(*-non-private-member-variables-in-classes)
352
      std::string negotiated_psk_identity;                     // NOLINT(*-non-private-member-variables-in-classes)
353
      std::map<std::string, std::vector<std::vector<uint8_t>>>
354
         serialized_messages;  // NOLINT(*-non-private-member-variables-in-classes)
355

356
   private:
357
      std::vector<uint8_t> send_buffer;
358
      std::vector<uint8_t> receive_buffer;
359
      uint64_t received_seq_no;
360
      Modify_Exts_Fn m_modify_exts;
361
      std::vector<MockSignature> m_mock_signatures;
362
      std::chrono::system_clock::time_point m_timestamp;
363

364
      mutable std::map<std::string, unsigned int> m_callback_invocations;
365
};
366

367
class Test_Credentials : public Botan::Credentials_Manager {
368
   public:
369
      explicit Test_Credentials(bool use_alternative_server_certificate, std::optional<ExternalPSK> external_psk) :
14✔
370
            m_alternative_server_certificate(use_alternative_server_certificate),
14✔
371
            m_external_psk(std::move(external_psk)) {
16✔
372
         Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/server_key.pem"));
28✔
373
         m_server_private_key.reset(Botan::PKCS8::load_key(in).release());
14✔
374

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

382
         m_client_private_key.reset(create_private_key("RSA", *rng, "1024").release());
28✔
383
      }
28✔
384

385
      std::vector<Botan::X509_Certificate> cert_chain(const std::vector<std::string>& cert_key_types,
5✔
386
                                                      const std::vector<AlgorithmIdentifier>& cert_signature_schemes,
387
                                                      const std::string& type,
388
                                                      const std::string& context) override {
389
         BOTAN_UNUSED(cert_key_types, cert_signature_schemes, context);
5✔
390
         return {(type == "tls-client")
5✔
391
                    ? client_certificate()
392
                    : ((m_alternative_server_certificate) ? alternative_server_certificate() : server_certificate())};
10✔
393
      }
394

395
      std::shared_ptr<Public_Key> find_raw_public_key(const std::vector<std::string>& key_types,
2✔
396
                                                      const std::string& type,
397
                                                      const std::string& context) override {
398
         BOTAN_UNUSED(key_types, type, context);
2✔
399
         return (type == "tls-client") ? client_raw_public_key_pair()->public_key()
3✔
400
                                       : server_raw_public_key_pair()->public_key();
5✔
401
      }
402

403
      std::shared_ptr<Botan::Private_Key> private_key_for(const Botan::X509_Certificate& cert,
5✔
404
                                                          const std::string& type,
405
                                                          const std::string& context) override {
406
         BOTAN_UNUSED(cert, context);
5✔
407

408
         if(type == "tls-client") {
5✔
409
            return m_client_private_key;
1✔
410
         }
411

412
         if(m_alternative_server_certificate) {
4✔
413
            return m_bogus_alternative_server_private_key;
1✔
414
         }
415

416
         return m_server_private_key;
3✔
417
      }
418

419
      std::shared_ptr<Botan::Private_Key> private_key_for(const Public_Key& raw_public_key,
2✔
420
                                                          const std::string& type,
421
                                                          const std::string& context) override {
422
         BOTAN_UNUSED(type, context);
2✔
423
         std::vector<std::unique_ptr<Botan::Private_Key>> keys;
2✔
424
         keys.emplace_back(client_raw_public_key_pair());
2✔
425
         keys.emplace_back(server_raw_public_key_pair());
2✔
426
         for(auto& key : keys) {
3✔
427
            if(key->fingerprint_public() == raw_public_key.fingerprint_public()) {
9✔
428
               return std::move(key);
2✔
429
            }
430
         }
431
         return nullptr;
×
432
      }
2✔
433

434
      std::vector<TLS::ExternalPSK> find_preshared_keys(std::string_view /* host */,
8✔
435
                                                        TLS::Connection_Side /* whoami */,
436
                                                        const std::vector<std::string>& identities,
437
                                                        const std::optional<std::string>& prf) override {
438
         if(!m_external_psk.has_value()) {
8✔
439
            return {};
6✔
440
         }
441

442
         ExternalPSK& epsk = m_external_psk.value();
2✔
443
         const auto found = std::find(identities.begin(), identities.end(), epsk.identity());
2✔
444
         if(!identities.empty() && found == identities.end()) {
2✔
445
            return {};
×
446
         }
447

448
         if(prf && prf != epsk.prf_algo()) {
2✔
449
            return {};
×
450
         }
451

452
         // ExternalPSK has a deleted copy constructor. We need to do some gymnastics
453
         // to copy it and leave the data in m_external_psk intact
454
         const auto secret = epsk.extract_master_secret();
2✔
455
         m_external_psk = ExternalPSK(epsk.identity(), epsk.prf_algo(), secret);
2✔
456
         std::vector<ExternalPSK> psks;
2✔
457
         psks.emplace_back(epsk.identity(), epsk.prf_algo(), secret);
2✔
458
         return psks;
2✔
459
      }
10✔
460

461
   private:
462
      bool m_alternative_server_certificate;
463
      std::optional<ExternalPSK> m_external_psk;
464
      std::shared_ptr<Private_Key> m_client_private_key;
465
      std::shared_ptr<Private_Key> m_bogus_alternative_server_private_key;
466
      std::shared_ptr<Private_Key> m_server_private_key;
467
};
468

469
class RFC8448_Text_Policy : public Botan::TLS::Text_Policy {
14✔
470
   private:
471
      Botan::TLS::Text_Policy read_policy(const std::string& policy_file) {
14✔
472
         const std::string fspath = Test::data_file("tls-policy/" + policy_file + ".txt");
28✔
473

474
         std::ifstream is(fspath.c_str());
14✔
475
         if(!is.good()) {
14✔
476
            throw Test_Error("Missing policy file " + fspath);
×
477
         }
478

479
         return Botan::TLS::Text_Policy(is);
14✔
480
      }
28✔
481

482
   public:
483
      RFC8448_Text_Policy(const std::string& policy_file, bool rfc8448 = true) :
14✔
484
            Botan::TLS::Text_Policy(read_policy(policy_file)), m_rfc8448(rfc8448) {}
14✔
485

486
      std::vector<Botan::TLS::Signature_Scheme> allowed_signature_schemes() const override {
16✔
487
         if(!m_rfc8448) {
16✔
488
            return Botan::TLS::Text_Policy::allowed_signature_schemes();
1✔
489
         }
490

491
         // We extend the allowed signature schemes with algorithms that we don't
492
         // actually support. The nature of the RFC 8448 test forces us to generate
493
         // bit-compatible TLS messages. Unfortunately, the test data offers all
494
         // those algorithms in its Client Hellos.
495
         return {
15✔
496
            Botan::TLS::Signature_Scheme::ECDSA_SHA256,
497
            Botan::TLS::Signature_Scheme::ECDSA_SHA384,
498
            Botan::TLS::Signature_Scheme::ECDSA_SHA512,
499
            Botan::TLS::Signature_Scheme::ECDSA_SHA1,  // not actually supported
500
            Botan::TLS::Signature_Scheme::RSA_PSS_SHA256,
501
            Botan::TLS::Signature_Scheme::RSA_PSS_SHA384,
502
            Botan::TLS::Signature_Scheme::RSA_PSS_SHA512,
503
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA256,
504
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA384,
505
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA512,
506
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA1,  // not actually supported
507
            Botan::TLS::Signature_Scheme(0x0402),          // DSA_SHA256, not actually supported
508
            Botan::TLS::Signature_Scheme(0x0502),          // DSA_SHA384, not actually supported
509
            Botan::TLS::Signature_Scheme(0x0602),          // DSA_SHA512, not actually supported
510
            Botan::TLS::Signature_Scheme(0x0202),          // DSA_SHA1, not actually supported
511
         };
15✔
512
      }
513

514
      // Overriding the key exchange group selection to favour the server's key
515
      // exchange group preference. This is required to enforce a Hello Retry Request
516
      // when testing RFC 8448 5. from the server side.
517
      Named_Group choose_key_exchange_group(const std::vector<Group_Params>& supported_by_peer,
8✔
518
                                            const std::vector<Group_Params>& offered_by_peer) const override {
519
         BOTAN_UNUSED(offered_by_peer);
8✔
520

521
         const auto supported_by_us = key_exchange_groups();
8✔
522
         const auto selected_group =
8✔
523
            std::find_if(supported_by_us.begin(), supported_by_us.end(), [&](const auto group) {
8✔
524
               return value_exists(supported_by_peer, group);
16✔
525
            });
526

527
         return selected_group != supported_by_us.end() ? *selected_group : Named_Group::NONE;
8✔
528
      }
8✔
529

530
   private:
531
      bool m_rfc8448;
532
};
533

534
/**
535
 * In-Memory Session Manager that stores sessions verbatim, without encryption.
536
 * Therefor it is not dependent on a random number generator and can easily be
537
 * instrumented for test inspection.
538
 */
539
class RFC8448_Session_Manager : public Botan::TLS::Session_Manager {
540
   private:
541
      decltype(auto) find_by_handle(const Session_Handle& handle) {
3✔
542
         return [=](const Session_with_Handle& session) {
30✔
543
            if(session.handle.id().has_value() && handle.id().has_value() &&
4✔
544
               session.handle.id().value() == handle.id().value()) {
2✔
545
               return true;
546
            }
547
            if(session.handle.ticket().has_value() && handle.ticket().has_value() &&
8✔
548
               session.handle.ticket().value() == handle.ticket().value()) {
10✔
549
               return true;
2✔
550
            }
551
            return false;
552
         };
3✔
553
      }
554

555
   public:
556
      RFC8448_Session_Manager() : Session_Manager(std::make_shared<Botan::Null_RNG>()) {}
28✔
557

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

560
      void store(const Session& session, const Session_Handle& handle) override {
4✔
561
         m_sessions.push_back({session, handle});
4✔
562
      }
4✔
563

564
      std::optional<Session_Handle> establish(const Session& session, const std::optional<Session_ID>&, bool) override {
1✔
565
         // we assume that the 'mocked' session is already stored in the manager,
566
         // verify that it is equivalent to the one created by the testee and
567
         // return the associated handle stored with it
568

569
         if(m_sessions.size() != 1) {
1✔
570
            throw Botan_Tests::Test_Error("No mocked session handle available; Test bug?");
×
571
         }
572

573
         const auto& [mocked_session, handle] = m_sessions.front();
1✔
574
         if(mocked_session.master_secret() != session.master_secret()) {
1✔
575
            throw Botan_Tests::Test_Error("Generated session object does not match the expected mock");
×
576
         }
577

578
         return handle;
1✔
579
      }
580

581
      std::optional<Session> retrieve_one(const Session_Handle& handle) override {
2✔
582
         auto itr = std::find_if(m_sessions.begin(), m_sessions.end(), find_by_handle(handle));
2✔
583
         if(itr == m_sessions.end()) {
2✔
584
            return std::nullopt;
1✔
585
         } else {
586
            return itr->session;
3✔
587
         }
588
      }
589

590
      std::vector<Session_with_Handle> find_some(const Server_Information& info, const size_t) override {
7✔
591
         std::vector<Session_with_Handle> found_sessions;
7✔
592
         for(const auto& [session, handle] : m_sessions) {
8✔
593
            if(session.server_info() == info) {
1✔
594
               found_sessions.emplace_back(Session_with_Handle{session, handle});
2✔
595
            }
596
         }
597

598
         return found_sessions;
7✔
599
      }
×
600

601
      size_t remove(const Session_Handle& handle) override {
1✔
602
         // TODO: C++20 allows to simply implement the entire method like:
603
         //
604
         //   return std::erase_if(m_sessions, find_by_handle(handle));
605
         //
606
         // Unfortunately, at the time of this writing Android NDK shipped with
607
         // a std::erase_if that returns void.
608
         auto rm_itr = std::remove_if(m_sessions.begin(), m_sessions.end(), find_by_handle(handle));
1✔
609

610
         const auto elements_being_removed = std::distance(rm_itr, m_sessions.end());
1✔
611
         m_sessions.erase(rm_itr);
1✔
612
         return elements_being_removed;
1✔
613
      }
614

615
      size_t remove_all() override {
×
616
         const auto sessions = m_sessions.size();
×
617
         m_sessions.clear();
×
618
         return sessions;
×
619
      }
620

621
   private:
622
      std::vector<Session_with_Handle> m_sessions;
623
};
624

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

653
   public:
654
      virtual ~TLS_Context() = default;
70✔
655

656
      TLS_Context(TLS_Context&) = delete;
657
      TLS_Context& operator=(const TLS_Context&) = delete;
658

659
      TLS_Context(TLS_Context&&) = delete;
660
      TLS_Context& operator=(TLS_Context&&) = delete;
661

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

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

666
      uint64_t last_received_seq_no() const { return m_callbacks->last_received_seq_no(); }
4✔
667

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

682
         for(const auto& invoke : invokes) {
369✔
683
            if(invoke.second == 0) {
309✔
684
               continue;
×
685
            }
686
            result.confirm(
618✔
687
               invoke.first + " was expected (Context: " + context + ")",
618✔
688
               std::find(callback_names.cbegin(), callback_names.cend(), invoke.first) != callback_names.cend());
618✔
689
         }
690

691
         m_callbacks->reset_callback_invocation_counters();
60✔
692
      }
60✔
693

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

696
      const std::vector<Botan::X509_Certificate>& certs_verified() const { return m_callbacks->certificate_chain; }
1✔
697

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

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

702
      /**
703
       * Send application data through the secure channel
704
       */
705
      virtual void send(const std::vector<uint8_t>& data) = 0;
706

707
   protected:
708
      std::shared_ptr<Test_TLS_13_Callbacks> m_callbacks;  // NOLINT(*-non-private-member-variables-in-classes)
709
      std::shared_ptr<Test_Credentials> m_creds;           // NOLINT(*-non-private-member-variables-in-classes)
710

711
      std::shared_ptr<Botan::RandomNumberGenerator> m_rng;     // NOLINT(*-non-private-member-variables-in-classes)
712
      std::shared_ptr<RFC8448_Session_Manager> m_session_mgr;  // NOLINT(*-non-private-member-variables-in-classes)
713
      std::shared_ptr<const RFC8448_Text_Policy> m_policy;     // NOLINT(*-non-private-member-variables-in-classes)
714
};
715

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

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

743
      Botan::TLS::Client client;  // NOLINT(*-non-private-member-variables-in-classes)
744
};
745

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

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

768
      Botan::TLS::Server server;  // NOLINT(*-non-private-member-variables-in-classes)
769
};
770

771
void sort_extensions(Botan::TLS::Extensions& exts, const std::vector<Botan::TLS::Extension_Code>& expected_order) {
29✔
772
   for(const auto ext_type : expected_order) {
274✔
773
      auto ext = exts.take(ext_type);
245✔
774
      if(ext != nullptr) {
245✔
775
         exts.add(std::move(ext));
228✔
776
      }
777
   }
245✔
778
}
29✔
779

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

819
void add_renegotiation_extension(Botan::TLS::Extensions& exts) {
5✔
820
   // Renegotiation is not possible in TLS 1.3. Nevertheless, RFC 8448 requires
821
   // to add this to the Client Hello for reasons.
822
   exts.add(new Renegotiation_Extension());
5✔
823
}
5✔
824

825
void add_early_data_indication(Botan::TLS::Extensions& exts) {
1✔
826
   exts.add(new Botan::TLS::EarlyDataIndication());
1✔
827
}
1✔
828

829
std::vector<uint8_t> strip_message_header(const std::vector<uint8_t>& msg) {
31✔
830
   BOTAN_ASSERT_NOMSG(msg.size() >= 4);
31✔
831
   return {msg.begin() + 4, msg.end()};
31✔
832
}
833

834
std::vector<MockSignature> make_mock_signatures(const VarMap& vars) {
9✔
835
   std::vector<MockSignature> result;
9✔
836

837
   auto mock = [&](const std::string& msg, const std::string& sig) {
27✔
838
      if(vars.has_key(msg) && vars.has_key(sig)) {
47✔
839
         result.push_back({vars.get_opt_bin(msg), vars.get_opt_bin(sig)});
11✔
840
      }
841
   };
18✔
842

843
   mock("Server_MessageToSign", "Server_MessageSignature");
18✔
844
   mock("Client_MessageToSign", "Client_MessageSignature");
18✔
845

846
   return result;
9✔
847
}
×
848

849
}  // namespace
850

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

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

900
      virtual std::string side() const = 0;
901

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

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

966
class Test_TLS_RFC8448_Client : public Test_TLS_RFC8448 {
1✔
967
   private:
968
      std::string side() const override { return "Client"; }
7✔
969

970
      std::vector<Test::Result> simple_1_rtt(const VarMap& vars) override {
1✔
971
         auto rng = std::make_shared<Botan_Tests::Fixed_Output_RNG>("");
1✔
972

973
         // 32 - for client hello random
974
         // 32 - for KeyShare (eph. x25519 key pair)
975
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
976

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

986
               add_renegotiation_extension(exts);
1✔
987
               sort_rfc8448_extensions(exts, side);
1✔
988
            }
989
         };
1✔
990

991
         std::unique_ptr<Client_Context> ctx;
1✔
992

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

1002
                  result.confirm("client not closed", !ctx->client.is_closed());
2✔
1003
                  ctx->check_callback_invocations(result,
7✔
1004
                                                  "client hello prepared",
1005
                                                  {
1006
                                                     "tls_emit_data",
1007
                                                     "tls_inspect_handshake_msg_client_hello",
1008
                                                     "tls_modify_extensions_client_hello",
1009
                                                     "tls_generate_ephemeral_key",
1010
                                                     "tls_current_timestamp",
1011
                                                  });
1012

1013
                  result.test_eq("TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1014
               }),
1✔
1015

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

1025
                  ctx->client.received_data(server_hello_a);
1✔
1026
                  ctx->check_callback_invocations(result, "server hello partially received", {});
2✔
1027

1028
                  ctx->client.received_data(server_hello_b);
1✔
1029
                  ctx->check_callback_invocations(result,
5✔
1030
                                                  "server hello received",
1031
                                                  {"tls_inspect_handshake_msg_server_hello",
1032
                                                   "tls_examine_extensions_server_hello",
1033
                                                   "tls_ephemeral_key_agreement"});
1034

1035
                  result.confirm("client is not yet active", !ctx->client.is_active());
2✔
1036
                  result.confirm("handshake is not yet complete", !ctx->client.is_handshake_complete());
3✔
1037
               }),
3✔
1038

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

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

1064
                  result.test_eq(
3✔
1065
                     "correct handshake finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
3✔
1066
               }),
1✔
1067

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

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

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

1094
                                  ctx->check_callback_invocations(result, "application data sent", {"tls_emit_data"});
3✔
1095

1096
                                  result.test_eq("correct client application data",
3✔
1097
                                                 ctx->pull_send_buffer(),
2✔
1098
                                                 vars.get_req_bin("Record_Client_AppData"));
2✔
1099
                               }),
1✔
1100

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

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

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

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

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

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

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

1133
      std::vector<Test::Result> resumed_handshake_with_0_rtt(const VarMap& vars) override {
1✔
1134
         auto rng = std::make_unique<Botan_Tests::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"));
2✔
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));
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
            Botan_Tests::CHECK(
1161
               "Client Hello",
1162
               [&](Test::Result& result) {
1✔
1163
                  ctx = std::make_unique<Client_Context>(
3✔
1164
                     std::move(rng),
1✔
1165
                     std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
1166
                     vars.get_req_u64("CurrentTimestamp"),
4✔
1167
                     add_extensions_and_sort,
1✔
1168
                     std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
1169
                               Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1170

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

1182
                  result.test_eq("TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
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
      }
1✔
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 {
4✔
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));
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<Botan_Tests::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"));
2✔
1220

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

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

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

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

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

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

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

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

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

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

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

1303
                  result.test_eq("client finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
4✔
1304
               }),
1✔
1305

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

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

1319
                  result.confirm("connection is closed", ctx->client.is_closed());
2✔
1320
               }),
1✔
1321
         };
6✔
1322
      }
1✔
1323

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

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

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

1340
         std::unique_ptr<Client_Context> ctx;
1✔
1341

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

1354
                  ctx->check_callback_invocations(result,
7✔
1355
                                                  "initial callbacks",
1356
                                                  {
1357
                                                     "tls_emit_data",
1358
                                                     "tls_inspect_handshake_msg_client_hello",
1359
                                                     "tls_modify_extensions_client_hello",
1360
                                                     "tls_generate_ephemeral_key",
1361
                                                     "tls_current_timestamp",
1362
                                                  });
1363

1364
                  result.test_eq("Client Hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1365
               }),
1✔
1366

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

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

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

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

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

1414
            Botan_Tests::CHECK(
1415
               "Close Connection",
1416
               [&](Test::Result& result) {
1✔
1417
                  result.require("ctx is available", ctx != nullptr);
2✔
1418
                  ctx->client.close();
1✔
1419
                  result.test_eq(
2✔
1420
                     "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
4✔
1421

1422
                  ctx->check_callback_invocations(result,
3✔
1423
                                                  "after sending close notify",
1424
                                                  {
1425
                                                     "tls_emit_data",
1426
                                                  });
1427

1428
                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1429
                  result.confirm("connection closed", ctx->client.is_closed());
2✔
1430

1431
                  ctx->check_callback_invocations(
4✔
1432
                     result, "after receiving close notify", {"tls_alert", "tls_peer_closed_connection"});
1433
               }),
1✔
1434
         };
5✔
1435
      }
1✔
1436

1437
      std::vector<Test::Result> middlebox_compatibility(const VarMap& vars) override {
1✔
1438
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>("");
1✔
1439

1440
         // 32 - client hello random
1441
         // 32 - legacy session ID
1442
         // 32 - eph. x25519 key pair
1443
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1444

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

1454
         std::unique_ptr<Client_Context> ctx;
1✔
1455

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

1465
                  result.test_eq("Client Hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1466

1467
                  ctx->check_callback_invocations(result,
7✔
1468
                                                  "client hello prepared",
1469
                                                  {
1470
                                                     "tls_emit_data",
1471
                                                     "tls_inspect_handshake_msg_client_hello",
1472
                                                     "tls_modify_extensions_client_hello",
1473
                                                     "tls_generate_ephemeral_key",
1474
                                                     "tls_current_timestamp",
1475
                                                  });
1476
               }),
1✔
1477

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

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

1506
                                  result.test_eq("CCS + Client Finished",
3✔
1507
                                                 ctx->pull_send_buffer(),
2✔
1508
                                                 // ClientFinished contains the expected ChangeCipherSpec record
1509
                                                 vars.get_req_bin("Record_ClientFinished"));
2✔
1510

1511
                                  result.confirm("client is ready to send application traffic",
2✔
1512
                                                 ctx->client.is_active());
1✔
1513
                                  result.confirm("handshake is complete", ctx->client.is_handshake_complete());
2✔
1514
                               }),
1✔
1515

1516
            Botan_Tests::CHECK(
1517
               "Close connection",
1518
               [&](Test::Result& result) {
1✔
1519
                  result.require("ctx is available", ctx != nullptr);
2✔
1520
                  ctx->client.close();
1✔
1521

1522
                  result.test_eq(
2✔
1523
                     "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
4✔
1524

1525
                  result.require("client cannot send application traffic anymore", !ctx->client.is_active());
1✔
1526
                  result.require("client is not fully closed yet", !ctx->client.is_closed());
1✔
1527
                  result.confirm("handshake stays completed", ctx->client.is_handshake_complete());
2✔
1528

1529
                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1530

1531
                  result.confirm("client connection was terminated", ctx->client.is_closed());
2✔
1532
               }),
1✔
1533
         };
4✔
1534
      }
1✔
1535

1536
      std::vector<Test::Result> externally_provided_psk_with_ephemeral_key(const VarMap& vars) override {
1✔
1537
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>("");
1✔
1538

1539
         // 32 - for client hello random
1540
         // 32 - for KeyShare (eph. x25519 key pair)
1541
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1542

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

1562
         std::unique_ptr<Client_Context> ctx;
1✔
1563

1564
         return {
1✔
1565
            Botan_Tests::CHECK(
1566
               "Client Hello",
1567
               [&](Test::Result& result) {
1✔
1568
                  ctx = std::make_unique<Client_Context>(
3✔
1569
                     std::move(rng),
1✔
1570
                     std::make_shared<RFC8448_Text_Policy>("rfc8448_psk_dhe", false /* no rfc8448 */),
1✔
1571
                     vars.get_req_u64("CurrentTimestamp"),
3✔
1572
                     sort_our_extensions,
1✔
1573
                     std::nullopt,
1574
                     ExternalPSK(vars.get_req_str("PskIdentity"),
2✔
1575
                                 vars.get_req_str("PskPRF"),
2✔
1576
                                 lock(vars.get_req_bin("PskSecret"))));
5✔
1577

1578
                  result.confirm("client not closed", !ctx->client.is_closed());
2✔
1579
                  ctx->check_callback_invocations(result,
7✔
1580
                                                  "client hello prepared",
1581
                                                  {
1582
                                                     "tls_emit_data",
1583
                                                     "tls_inspect_handshake_msg_client_hello",
1584
                                                     "tls_modify_extensions_client_hello",
1585
                                                     "tls_current_timestamp",
1586
                                                     "tls_generate_ephemeral_key",
1587
                                                  });
1588

1589
                  result.test_eq("TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1590
               }),
1✔
1591

1592
            Botan_Tests::CHECK("Server Hello",
1593
                               [&](Test::Result& result) {
1✔
1594
                                  result.require("ctx is available", ctx != nullptr);
1✔
1595
                                  const auto server_hello = vars.get_req_bin("Record_ServerHello");
1✔
1596
                                  ctx->client.received_data(server_hello);
1✔
1597
                                  ctx->check_callback_invocations(result,
5✔
1598
                                                                  "server hello received",
1599
                                                                  {"tls_inspect_handshake_msg_server_hello",
1600
                                                                   "tls_examine_extensions_server_hello",
1601
                                                                   "tls_ephemeral_key_agreement"});
1602

1603
                                  result.confirm("client is not yet active", !ctx->client.is_active());
2✔
1604
                                  result.confirm("handshake is not yet complete", !ctx->client.is_handshake_complete());
3✔
1605
                               }),
1✔
1606

1607
            Botan_Tests::CHECK(
1608
               "Server HS messages .. Client Finished",
1609
               [&](Test::Result& result) {
1✔
1610
                  result.require("ctx is available", ctx != nullptr);
3✔
1611
                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
1612

1613
                  ctx->check_callback_invocations(result,
9✔
1614
                                                  "encrypted handshake messages received",
1615
                                                  {"tls_inspect_handshake_msg_encrypted_extensions",
1616
                                                   "tls_inspect_handshake_msg_finished",
1617
                                                   "tls_examine_extensions_encrypted_extensions",
1618
                                                   "tls_emit_data",
1619
                                                   "tls_current_timestamp",
1620
                                                   "tls_session_established",
1621
                                                   "tls_session_activated"});
1622
                  result.require("PSK negotiated", ctx->psk_identity_negotiated() == vars.get_req_str("PskIdentity"));
2✔
1623
                  result.require("client is active", ctx->client.is_active());
1✔
1624
                  result.confirm("handshake is complete", ctx->client.is_handshake_complete());
2✔
1625

1626
                  result.test_eq(
3✔
1627
                     "correct handshake finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
3✔
1628
               }),
1✔
1629

1630
            Botan_Tests::CHECK("Send Application Data",
1631
                               [&](Test::Result& result) {
1✔
1632
                                  result.require("ctx is available", ctx != nullptr);
2✔
1633
                                  ctx->send(vars.get_req_bin("Client_AppData"));
3✔
1634

1635
                                  ctx->check_callback_invocations(result, "application data sent", {"tls_emit_data"});
3✔
1636

1637
                                  result.test_eq("correct client application data",
3✔
1638
                                                 ctx->pull_send_buffer(),
2✔
1639
                                                 vars.get_req_bin("Record_Client_AppData"));
2✔
1640
                               }),
1✔
1641

1642
            Botan_Tests::CHECK(
1643
               "Receive Application Data",
1644
               [&](Test::Result& result) {
1✔
1645
                  result.require("ctx is available", ctx != nullptr);
1✔
1646
                  ctx->client.received_data(vars.get_req_bin("Record_Server_AppData"));
2✔
1647

1648
                  ctx->check_callback_invocations(result, "application data sent", {"tls_record_received"});
3✔
1649

1650
                  const auto rcvd = ctx->pull_receive_buffer();
1✔
1651
                  result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Server_AppData"));
3✔
1652
                  result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
2✔
1653
               }),
1✔
1654

1655
            Botan_Tests::CHECK("Close Connection",
1656
                               [&](Test::Result& result) {
1✔
1657
                                  result.require("ctx is available", ctx != nullptr);
2✔
1658
                                  ctx->client.close();
1✔
1659

1660
                                  result.test_eq("close payload",
2✔
1661
                                                 ctx->pull_send_buffer(),
2✔
1662
                                                 vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1663
                                  ctx->check_callback_invocations(result, "CLOSE_NOTIFY sent", {"tls_emit_data"});
3✔
1664

1665
                                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1666
                                  ctx->check_callback_invocations(
4✔
1667
                                     result, "CLOSE_NOTIFY received", {"tls_alert", "tls_peer_closed_connection"});
1668

1669
                                  result.confirm("connection is closed", ctx->client.is_closed());
2✔
1670
                               }),
1✔
1671
         };
7✔
1672
      }
1✔
1673

1674
      std::vector<Test::Result> raw_public_key_with_client_authentication(const VarMap& vars) override {
1✔
1675
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>("");
1✔
1676

1677
         // 32 - for client hello random
1678
         // 32 - for KeyShare (eph. x25519 key pair)
1679
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1680

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

1702
         std::unique_ptr<Client_Context> ctx;
1✔
1703

1704
         return {
1✔
1705
            Botan_Tests::CHECK(
1706
               "Client Hello",
1707
               [&](Test::Result& result) {
1✔
1708
                  ctx = std::make_unique<Client_Context>(std::move(rng),
3✔
1709
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_rawpubkey"),
1✔
1710
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
1711
                                                         sort_our_extensions,
1✔
1712
                                                         std::nullopt,
1713
                                                         std::nullopt,
1714
                                                         make_mock_signatures(vars));
3✔
1715

1716
                  ctx->check_callback_invocations(result,
7✔
1717
                                                  "initial callbacks",
1718
                                                  {
1719
                                                     "tls_emit_data",
1720
                                                     "tls_inspect_handshake_msg_client_hello",
1721
                                                     "tls_modify_extensions_client_hello",
1722
                                                     "tls_generate_ephemeral_key",
1723
                                                     "tls_current_timestamp",
1724
                                                  });
1725

1726
                  result.test_eq("Client Hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1727
               }),
1✔
1728

1729
            Botan_Tests::CHECK("Server Hello",
1730
                               [&](auto& result) {
1✔
1731
                                  result.require("ctx is available", ctx != nullptr);
2✔
1732
                                  ctx->client.received_data(vars.get_req_bin("Record_ServerHello"));
3✔
1733

1734
                                  ctx->check_callback_invocations(result,
5✔
1735
                                                                  "callbacks after server hello",
1736
                                                                  {
1737
                                                                     "tls_examine_extensions_server_hello",
1738
                                                                     "tls_inspect_handshake_msg_server_hello",
1739
                                                                     "tls_ephemeral_key_agreement",
1740
                                                                  });
1741
                               }),
1✔
1742

1743
            Botan_Tests::CHECK("other handshake messages and client auth",
1744
                               [&](Test::Result& result) {
1✔
1745
                                  result.require("ctx is available", ctx != nullptr);
2✔
1746
                                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
1747

1748
                                  ctx->check_callback_invocations(result,
18✔
1749
                                                                  "signing callbacks invoked",
1750
                                                                  {
1751
                                                                     "tls_sign_message",
1752
                                                                     "tls_emit_data",
1753
                                                                     "tls_examine_extensions_encrypted_extensions",
1754
                                                                     "tls_examine_extensions_certificate",
1755
                                                                     "tls_examine_extensions_certificate_request",
1756
                                                                     "tls_modify_extensions_certificate",
1757
                                                                     "tls_inspect_handshake_msg_certificate",
1758
                                                                     "tls_inspect_handshake_msg_certificate_request",
1759
                                                                     "tls_inspect_handshake_msg_certificate_verify",
1760
                                                                     "tls_inspect_handshake_msg_encrypted_extensions",
1761
                                                                     "tls_inspect_handshake_msg_finished",
1762
                                                                     "tls_current_timestamp",
1763
                                                                     "tls_session_established",
1764
                                                                     "tls_session_activated",
1765
                                                                     "tls_verify_raw_public_key",
1766
                                                                     "tls_verify_message",
1767
                                                                  });
1768

1769
                                  const auto raw_pk = ctx->client.peer_raw_public_key();
1✔
1770
                                  result.confirm("Received server's raw public key",
2✔
1771
                                                 raw_pk && raw_pk->fingerprint_public() ==
3✔
1772
                                                              server_raw_public_key_pair()->fingerprint_public());
3✔
1773

1774
                                  // ClientFinished contains the entire coalesced client authentication flight
1775
                                  // Messages: Certificate, CertificateVerify, Finished
1776
                                  result.test_eq("Client Auth and Finished",
3✔
1777
                                                 ctx->pull_send_buffer(),
2✔
1778
                                                 vars.get_req_bin("Record_ClientFinished"));
3✔
1779
                               }),
1✔
1780

1781
            Botan_Tests::CHECK(
1782
               "Close Connection",
1783
               [&](Test::Result& result) {
1✔
1784
                  result.require("ctx is available", ctx != nullptr);
2✔
1785
                  ctx->client.close();
1✔
1786
                  result.test_eq(
2✔
1787
                     "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
4✔
1788

1789
                  ctx->check_callback_invocations(result,
3✔
1790
                                                  "after sending close notify",
1791
                                                  {
1792
                                                     "tls_emit_data",
1793
                                                  });
1794

1795
                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1796
                  result.confirm("connection closed", ctx->client.is_closed());
2✔
1797

1798
                  ctx->check_callback_invocations(
4✔
1799
                     result, "after receiving close notify", {"tls_alert", "tls_peer_closed_connection"});
1800
               }),
1✔
1801
         };
5✔
1802
      }
1✔
1803
};
1804

1805
class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 {
1✔
1806
   private:
1807
      std::string side() const override { return "Server"; }
7✔
1808

1809
      std::vector<Test::Result> simple_1_rtt(const VarMap& vars) override {
1✔
1810
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>("");
1✔
1811

1812
         // 32 - for server hello random
1813
         // 32 - for KeyShare (eph. x25519 key pair)  --  I guess?
1814
         //  4 - for ticket_age_add (in New Session Ticket)
1815
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1816

1817
         std::unique_ptr<Server_Context> ctx;
1✔
1818

1819
         return {
1✔
1820
            Botan_Tests::CHECK("Send Client Hello",
1821
                               [&](Test::Result& result) {
1✔
1822
                                  auto add_early_data_and_sort = [&](Botan::TLS::Extensions& exts,
5✔
1823
                                                                     Botan::TLS::Connection_Side side,
1824
                                                                     Botan::TLS::Handshake_Type type) {
1825
                                     if(type == Handshake_Type::NewSessionTicket) {
4✔
1826
                                        exts.add(new EarlyDataIndication(1024));
1✔
1827
                                     }
1828
                                     sort_rfc8448_extensions(exts, side, type);
4✔
1829
                                  };
4✔
1830

1831
                                  ctx = std::make_unique<Server_Context>(
2✔
1832
                                     std::move(rng),
1✔
1833
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
1834
                                     vars.get_req_u64("CurrentTimestamp"),
5✔
1835
                                     add_early_data_and_sort,
1836
                                     make_mock_signatures(vars),
1✔
1837
                                     false,
2✔
1838
                                     std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
1839
                                               Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1840
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
1841

1842
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1843

1844
                                  ctx->check_callback_invocations(result,
16✔
1845
                                                                  "client hello received",
1846
                                                                  {"tls_emit_data",
1847
                                                                   "tls_examine_extensions_client_hello",
1848
                                                                   "tls_modify_extensions_server_hello",
1849
                                                                   "tls_modify_extensions_encrypted_extensions",
1850
                                                                   "tls_modify_extensions_certificate",
1851
                                                                   "tls_sign_message",
1852
                                                                   "tls_generate_ephemeral_key",
1853
                                                                   "tls_ephemeral_key_agreement",
1854
                                                                   "tls_inspect_handshake_msg_client_hello",
1855
                                                                   "tls_inspect_handshake_msg_server_hello",
1856
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
1857
                                                                   "tls_inspect_handshake_msg_certificate",
1858
                                                                   "tls_inspect_handshake_msg_certificate_verify",
1859
                                                                   "tls_inspect_handshake_msg_finished"});
1860
                               }),
1✔
1861

1862
            Botan_Tests::CHECK("Verify generated messages in server's first flight",
1863
                               [&](Test::Result& result) {
1✔
1864
                                  result.require("ctx is available", ctx != nullptr);
1✔
1865
                                  const auto& msgs = ctx->observed_handshake_messages();
1✔
1866

1867
                                  result.test_eq("Server Hello",
2✔
1868
                                                 msgs.at("server_hello")[0],
2✔
1869
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
1870
                                  result.test_eq("Encrypted Extensions",
3✔
1871
                                                 msgs.at("encrypted_extensions")[0],
2✔
1872
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
1873
                                  result.test_eq("Certificate",
3✔
1874
                                                 msgs.at("certificate")[0],
2✔
1875
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
1876
                                  result.test_eq(
3✔
1877
                                     "CertificateVerify",
1878
                                     msgs.at("certificate_verify")[0],
2✔
1879
                                     strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
1880

1881
                                  result.test_eq("Server's entire first flight",
3✔
1882
                                                 ctx->pull_send_buffer(),
2✔
1883
                                                 concat(vars.get_req_bin("Record_ServerHello"),
5✔
1884
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1885

1886
                                  // Note: is_active() defines that we can send application data.
1887
                                  //       RFC 8446 Section 4.4.4 explicitly allows that for servers
1888
                                  //       that did not receive the client's Finished message, yet.
1889
                                  //       However, before receiving and validating this message,
1890
                                  //       the handshake is not yet finished.
1891
                                  result.confirm("Server can now send application data", ctx->server.is_active());
2✔
1892
                                  result.confirm("handshake is not yet complete", !ctx->server.is_handshake_complete());
3✔
1893
                               }),
1✔
1894

1895
            Botan_Tests::CHECK("Send Client Finished",
1896
                               [&](Test::Result& result) {
1✔
1897
                                  result.require("ctx is available", ctx != nullptr);
1✔
1898
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
1899

1900
                                  ctx->check_callback_invocations(result,
6✔
1901
                                                                  "client finished received",
1902
                                                                  {"tls_inspect_handshake_msg_finished",
1903
                                                                   "tls_current_timestamp",
1904
                                                                   "tls_session_established",
1905
                                                                   "tls_session_activated"});
1906
                               }),
1✔
1907

1908
            Botan_Tests::CHECK("Send Session Ticket",
1909
                               [&](Test::Result& result) {
1✔
1910
                                  result.require("ctx is available", ctx != nullptr);
1✔
1911
                                  const auto new_tickets = ctx->server.send_new_session_tickets(1);
1✔
1912

1913
                                  result.test_eq("session ticket was sent", new_tickets, 1);
1✔
1914

1915
                                  ctx->check_callback_invocations(result,
7✔
1916
                                                                  "issued new session ticket",
1917
                                                                  {"tls_inspect_handshake_msg_new_session_ticket",
1918
                                                                   "tls_current_timestamp",
1919
                                                                   "tls_emit_data",
1920
                                                                   "tls_modify_extensions_new_session_ticket",
1921
                                                                   "tls_should_persist_resumption_information"});
1922
                               }),
1✔
1923

1924
            Botan_Tests::CHECK("Verify generated new session ticket message",
1925
                               [&](Test::Result& result) {
1✔
1926
                                  result.require("ctx is available", ctx != nullptr);
2✔
1927
                                  result.test_eq("New Session Ticket",
2✔
1928
                                                 ctx->pull_send_buffer(),
2✔
1929
                                                 vars.get_req_bin("Record_NewSessionTicket"));
2✔
1930
                               }),
1✔
1931

1932
            Botan_Tests::CHECK(
1933
               "Receive Application Data",
1934
               [&](Test::Result& result) {
1✔
1935
                  result.require("ctx is available", ctx != nullptr);
1✔
1936
                  ctx->server.received_data(vars.get_req_bin("Record_Client_AppData"));
2✔
1937
                  ctx->check_callback_invocations(result, "application data received", {"tls_record_received"});
3✔
1938

1939
                  const auto rcvd = ctx->pull_receive_buffer();
1✔
1940
                  result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Client_AppData"));
3✔
1941
                  result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
2✔
1942
               }),
1✔
1943

1944
            Botan_Tests::CHECK("Send Application Data",
1945
                               [&](Test::Result& result) {
1✔
1946
                                  result.require("ctx is available", ctx != nullptr);
2✔
1947
                                  ctx->send(vars.get_req_bin("Server_AppData"));
3✔
1948

1949
                                  ctx->check_callback_invocations(result, "application data sent", {"tls_emit_data"});
3✔
1950

1951
                                  result.test_eq("correct server application data",
3✔
1952
                                                 ctx->pull_send_buffer(),
2✔
1953
                                                 vars.get_req_bin("Record_Server_AppData"));
2✔
1954
                               }),
1✔
1955

1956
            Botan_Tests::CHECK("Receive Client's close_notify",
1957
                               [&](Test::Result& result) {
1✔
1958
                                  result.require("ctx is available", ctx != nullptr);
1✔
1959
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
1960

1961
                                  ctx->check_callback_invocations(
4✔
1962
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
1963

1964
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
1965
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
1966
                                  result.confirm("handshake is still finished", ctx->server.is_handshake_complete());
2✔
1967
                               }),
1✔
1968

1969
            Botan_Tests::CHECK("Expect Server close_notify",
1970
                               [&](Test::Result& result) {
1✔
1971
                                  result.require("ctx is available", ctx != nullptr);
2✔
1972
                                  ctx->server.close();
1✔
1973

1974
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
1975
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
1976
                                  result.confirm("handshake is still finished", ctx->server.is_handshake_complete());
2✔
1977
                                  result.test_eq("Server's close notify",
2✔
1978
                                                 ctx->pull_send_buffer(),
2✔
1979
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1980
                               }),
1✔
1981
         };
10✔
1982
      }
1✔
1983

1984
      std::vector<Test::Result> resumed_handshake_with_0_rtt(const VarMap& vars) override {
1✔
1985
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>();
1✔
1986

1987
         // 32 - for server hello random
1988
         // 32 - for KeyShare (eph. x25519 key pair)
1989
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1990

1991
         std::unique_ptr<Server_Context> ctx;
1✔
1992

1993
         return {
1✔
1994
            Botan_Tests::CHECK("Receive Client Hello",
1995
                               [&](Test::Result& result) {
1✔
1996
                                  auto add_cookie_and_sort = [&](Botan::TLS::Extensions& exts,
3✔
1997
                                                                 Botan::TLS::Connection_Side side,
1998
                                                                 Botan::TLS::Handshake_Type type) {
1999
                                     if(type == Handshake_Type::EncryptedExtensions) {
2✔
2000
                                        exts.add(new EarlyDataIndication());
1✔
2001
                                     }
2002
                                     sort_rfc8448_extensions(exts, side, type);
2✔
2003
                                  };
2✔
2004

2005
                                  ctx = std::make_unique<Server_Context>(
2✔
2006
                                     std::move(rng),
1✔
2007
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
2008
                                     vars.get_req_u64("CurrentTimestamp"),
5✔
2009
                                     add_cookie_and_sort,
2010
                                     make_mock_signatures(vars),
1✔
2011
                                     false,
2✔
2012
                                     std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
2013
                                               Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
2014
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
2015

2016
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2017

2018
                                  ctx->check_callback_invocations(result,
13✔
2019
                                                                  "client hello received",
2020
                                                                  {
2021
                                                                     "tls_emit_data",
2022
                                                                     "tls_current_timestamp",
2023
                                                                     "tls_generate_ephemeral_key",
2024
                                                                     "tls_ephemeral_key_agreement",
2025
                                                                     "tls_examine_extensions_client_hello",
2026
                                                                     "tls_modify_extensions_server_hello",
2027
                                                                     "tls_modify_extensions_encrypted_extensions",
2028
                                                                     "tls_inspect_handshake_msg_client_hello",
2029
                                                                     "tls_inspect_handshake_msg_server_hello",
2030
                                                                     "tls_inspect_handshake_msg_encrypted_extensions",
2031
                                                                     "tls_inspect_handshake_msg_finished",
2032
                                                                  });
2033
                               }),
1✔
2034

2035
            Botan_Tests::CHECK("Verify generated messages in server's first flight",
2036
                               [&](Test::Result& result) {
1✔
2037
                                  result.require("ctx is available", ctx != nullptr);
1✔
2038
                                  const auto& msgs = ctx->observed_handshake_messages();
1✔
2039

2040
                                  result.test_eq("Server Hello",
2✔
2041
                                                 msgs.at("server_hello")[0],
2✔
2042
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
2043
                                  result.test_eq("Encrypted Extensions",
3✔
2044
                                                 msgs.at("encrypted_extensions")[0],
2✔
2045
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2046

2047
                                  result.test_eq("Server's entire first flight",
3✔
2048
                                                 ctx->pull_send_buffer(),
2✔
2049
                                                 concat(vars.get_req_bin("Record_ServerHello"),
5✔
2050
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2051

2052
                                  // Note: is_active() defines that we can send application data.
2053
                                  //       RFC 8446 Section 4.4.4 explicitly allows that for servers
2054
                                  //       that did not receive the client's Finished message, yet.
2055
                                  //       However, before receiving and validating this message,
2056
                                  //       the handshake is not yet finished.
2057
                                  result.confirm("Server can now send application data", ctx->server.is_active());
2✔
2058
                                  result.confirm("handshake is not yet complete", !ctx->server.is_handshake_complete());
3✔
2059
                               }),
1✔
2060

2061
            // TODO: The rest of this test vector requires 0-RTT which is not
2062
            //       yet implemented. For now we can only test the server's
2063
            //       ability to acknowledge a session resumption via PSK.
2064
         };
3✔
2065
      }
1✔
2066

2067
      std::vector<Test::Result> hello_retry_request(const VarMap& vars) override {
1✔
2068
         // Fallback RNG is required to for blinding in ECDH with P-256
2069
         auto& fallback_rng = this->rng();
1✔
2070
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>(fallback_rng);
1✔
2071

2072
         // 32 - for server hello random
2073
         // 32 - for KeyShare (eph. P-256 key pair)
2074
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2075

2076
         std::unique_ptr<Server_Context> ctx;
1✔
2077

2078
         return {
1✔
2079
            Botan_Tests::CHECK("Receive Client Hello",
2080
                               [&](Test::Result& result) {
1✔
2081
                                  auto add_cookie_and_sort = [&](Botan::TLS::Extensions& exts,
5✔
2082
                                                                 Botan::TLS::Connection_Side side,
2083
                                                                 Botan::TLS::Handshake_Type type) {
2084
                                     if(type == Handshake_Type::HelloRetryRequest) {
4✔
2085
                                        // This cookie needs to be mocked into the HRR since RFC 8448 contains it.
2086
                                        exts.add(new Cookie(vars.get_opt_bin("HelloRetryRequest_Cookie")));
5✔
2087
                                     }
2088
                                     sort_rfc8448_extensions(exts, side, type);
4✔
2089
                                  };
4✔
2090

2091
                                  ctx = std::make_unique<Server_Context>(
2✔
2092
                                     std::move(rng),
1✔
2093
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_hrr_server"),
1✔
2094
                                     vars.get_req_u64("CurrentTimestamp"),
2✔
2095
                                     add_cookie_and_sort,
2096
                                     make_mock_signatures(vars));
3✔
2097
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
2098

2099
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2100

2101
                                  ctx->check_callback_invocations(result,
7✔
2102
                                                                  "client hello received",
2103
                                                                  {"tls_emit_data",
2104
                                                                   "tls_examine_extensions_client_hello",
2105
                                                                   "tls_modify_extensions_hello_retry_request",
2106
                                                                   "tls_inspect_handshake_msg_client_hello",
2107
                                                                   "tls_inspect_handshake_msg_hello_retry_request"});
2108
                               }),
1✔
2109

2110
            Botan_Tests::CHECK("Verify generated Hello Retry Request message",
2111
                               [&](Test::Result& result) {
1✔
2112
                                  result.require("ctx is available", ctx != nullptr);
2✔
2113
                                  result.test_eq("Server's Hello Retry Request record",
2✔
2114
                                                 ctx->pull_send_buffer(),
2✔
2115
                                                 vars.get_req_bin("Record_HelloRetryRequest"));
2✔
2116
                                  result.confirm("TLS handshake not yet finished", !ctx->server.is_active());
2✔
2117
                                  result.confirm("handshake is not yet complete", !ctx->server.is_handshake_complete());
2✔
2118
                               }),
1✔
2119

2120
            Botan_Tests::CHECK("Receive updated Client Hello message",
2121
                               [&](Test::Result& result) {
1✔
2122
                                  result.require("ctx is available", ctx != nullptr);
1✔
2123
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_2"));
2✔
2124

2125
                                  ctx->check_callback_invocations(result,
16✔
2126
                                                                  "updated client hello received",
2127
                                                                  {"tls_emit_data",
2128
                                                                   "tls_examine_extensions_client_hello",
2129
                                                                   "tls_modify_extensions_server_hello",
2130
                                                                   "tls_modify_extensions_encrypted_extensions",
2131
                                                                   "tls_modify_extensions_certificate",
2132
                                                                   "tls_sign_message",
2133
                                                                   "tls_generate_ephemeral_key",
2134
                                                                   "tls_ephemeral_key_agreement",
2135
                                                                   "tls_inspect_handshake_msg_client_hello",
2136
                                                                   "tls_inspect_handshake_msg_server_hello",
2137
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
2138
                                                                   "tls_inspect_handshake_msg_certificate",
2139
                                                                   "tls_inspect_handshake_msg_certificate_verify",
2140
                                                                   "tls_inspect_handshake_msg_finished"});
2141
                               }),
1✔
2142

2143
            Botan_Tests::CHECK("Verify generated messages in server's second flight",
2144
                               [&](Test::Result& result) {
1✔
2145
                                  result.require("ctx is available", ctx != nullptr);
1✔
2146
                                  const auto& msgs = ctx->observed_handshake_messages();
1✔
2147

2148
                                  result.test_eq("Server Hello",
2✔
2149
                                                 msgs.at("server_hello")[0],
2✔
2150
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
2151
                                  result.test_eq("Encrypted Extensions",
3✔
2152
                                                 msgs.at("encrypted_extensions")[0],
2✔
2153
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2154
                                  result.test_eq("Certificate",
3✔
2155
                                                 msgs.at("certificate")[0],
2✔
2156
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
2157
                                  result.test_eq(
3✔
2158
                                     "CertificateVerify",
2159
                                     msgs.at("certificate_verify")[0],
2✔
2160
                                     strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
2161
                                  result.test_eq("Finished",
3✔
2162
                                                 msgs.at("finished")[0],
2✔
2163
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2164

2165
                                  result.test_eq("Server's entire second flight",
3✔
2166
                                                 ctx->pull_send_buffer(),
2✔
2167
                                                 concat(vars.get_req_bin("Record_ServerHello"),
5✔
2168
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2169
                                  result.confirm("Server could now send application data", ctx->server.is_active());
2✔
2170
                                  result.confirm("handshake is not yet complete",
3✔
2171
                                                 !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2172
                               }),
1✔
2173

2174
            Botan_Tests::CHECK("Receive Client Finished",
2175
                               [&](Test::Result& result) {
1✔
2176
                                  result.require("ctx is available", ctx != nullptr);
1✔
2177
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2178

2179
                                  ctx->check_callback_invocations(result,
6✔
2180
                                                                  "client finished received",
2181
                                                                  {"tls_inspect_handshake_msg_finished",
2182
                                                                   "tls_current_timestamp",
2183
                                                                   "tls_session_established",
2184
                                                                   "tls_session_activated"});
2185

2186
                                  result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2187
                                  result.confirm("handshake is complete", ctx->server.is_handshake_complete());
2✔
2188
                               }),
1✔
2189

2190
            Botan_Tests::CHECK("Receive Client close_notify",
2191
                               [&](Test::Result& result) {
1✔
2192
                                  result.require("ctx is available", ctx != nullptr);
1✔
2193
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2194

2195
                                  ctx->check_callback_invocations(
4✔
2196
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2197

2198
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2199
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
2200
                                  result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2201
                               }),
1✔
2202

2203
            Botan_Tests::CHECK("Expect Server close_notify",
2204
                               [&](Test::Result& result) {
1✔
2205
                                  result.require("ctx is available", ctx != nullptr);
2✔
2206
                                  ctx->server.close();
1✔
2207

2208
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2209
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2210
                                  result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2211
                                  result.test_eq("Server's close notify",
2✔
2212
                                                 ctx->pull_send_buffer(),
2✔
2213
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2214
                               }),
1✔
2215

2216
         };
8✔
2217
      }
1✔
2218

2219
      std::vector<Test::Result> client_authentication(const VarMap& vars) override {
1✔
2220
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>("");
1✔
2221

2222
         // 32 - for server hello random
2223
         // 32 - for KeyShare (eph. x25519 pair)
2224
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2225

2226
         std::unique_ptr<Server_Context> ctx;
1✔
2227

2228
         return {
1✔
2229
            Botan_Tests::CHECK("Receive Client Hello",
2230
                               [&](Test::Result& result) {
1✔
2231
                                  ctx = std::make_unique<Server_Context>(
2✔
2232
                                     std::move(rng),
1✔
2233
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_client_auth_server"),
1✔
2234
                                     vars.get_req_u64("CurrentTimestamp"),
3✔
2235
                                     sort_rfc8448_extensions,
2236
                                     make_mock_signatures(vars),
1✔
2237
                                     true /* use alternative certificate */);
2✔
2238
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
2239

2240
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2241

2242
                                  ctx->check_callback_invocations(result,
17✔
2243
                                                                  "client hello received",
2244
                                                                  {"tls_emit_data",
2245
                                                                   "tls_examine_extensions_client_hello",
2246
                                                                   "tls_modify_extensions_server_hello",
2247
                                                                   "tls_modify_extensions_encrypted_extensions",
2248
                                                                   "tls_modify_extensions_certificate",
2249
                                                                   "tls_sign_message",
2250
                                                                   "tls_generate_ephemeral_key",
2251
                                                                   "tls_ephemeral_key_agreement",
2252
                                                                   "tls_inspect_handshake_msg_client_hello",
2253
                                                                   "tls_inspect_handshake_msg_server_hello",
2254
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
2255
                                                                   "tls_inspect_handshake_msg_certificate_request",
2256
                                                                   "tls_inspect_handshake_msg_certificate",
2257
                                                                   "tls_inspect_handshake_msg_certificate_verify",
2258
                                                                   "tls_inspect_handshake_msg_finished"});
2259
                               }),
1✔
2260

2261
            Botan_Tests::CHECK(
2262
               "Verify server's generated handshake messages",
2263
               [&](Test::Result& result) {
1✔
2264
                  result.require("ctx is available", ctx != nullptr);
1✔
2265
                  const auto& msgs = ctx->observed_handshake_messages();
1✔
2266

2267
                  result.test_eq("Server Hello",
2✔
2268
                                 msgs.at("server_hello")[0],
2✔
2269
                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
2270
                  result.test_eq("Encrypted Extensions",
3✔
2271
                                 msgs.at("encrypted_extensions")[0],
2✔
2272
                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2273
                  result.test_eq("Certificate Request",
3✔
2274
                                 msgs.at("certificate_request")[0],
2✔
2275
                                 strip_message_header(vars.get_opt_bin("Message_CertificateRequest")));
3✔
2276
                  result.test_eq("Certificate",
3✔
2277
                                 msgs.at("certificate")[0],
2✔
2278
                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
2279
                  result.test_eq("CertificateVerify",
3✔
2280
                                 msgs.at("certificate_verify")[0],
2✔
2281
                                 strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
2282
                  result.test_eq("Finished",
3✔
2283
                                 msgs.at("finished")[0],
2✔
2284
                                 strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2285

2286
                  result.test_eq("Server's entire first flight",
3✔
2287
                                 ctx->pull_send_buffer(),
2✔
2288
                                 concat(vars.get_req_bin("Record_ServerHello"),
5✔
2289
                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2290

2291
                  result.confirm("Not yet aware of client's cert chain", ctx->server.peer_cert_chain().empty());
3✔
2292
                  result.confirm("Server could now send application data", ctx->server.is_active());
2✔
2293
                  result.confirm("handshake is not yet complete",
3✔
2294
                                 !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2295
               }),
1✔
2296

2297
            Botan_Tests::CHECK("Receive Client's second flight",
2298
                               [&](Test::Result& result) {
1✔
2299
                                  result.require("ctx is available", ctx != nullptr);
1✔
2300
                                  // This encrypted message contains the following messages:
2301
                                  // * client's Certificate message
2302
                                  // * client's Certificate_Verify message
2303
                                  // * client's Finished message
2304
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2305

2306
                                  ctx->check_callback_invocations(result,
11✔
2307
                                                                  "client finished received",
2308
                                                                  {"tls_inspect_handshake_msg_certificate",
2309
                                                                   "tls_inspect_handshake_msg_certificate_verify",
2310
                                                                   "tls_inspect_handshake_msg_finished",
2311
                                                                   "tls_examine_extensions_certificate",
2312
                                                                   "tls_verify_cert_chain",
2313
                                                                   "tls_verify_message",
2314
                                                                   "tls_current_timestamp",
2315
                                                                   "tls_session_established",
2316
                                                                   "tls_session_activated"});
2317

2318
                                  const auto cert_chain = ctx->server.peer_cert_chain();
1✔
2319
                                  result.confirm("Received client's cert chain",
2✔
2320
                                                 !cert_chain.empty() && cert_chain.front() == client_certificate());
2✔
2321

2322
                                  result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2323
                                  result.confirm("handshake is complete", ctx->server.is_handshake_complete());
2✔
2324
                               }),
1✔
2325

2326
            Botan_Tests::CHECK("Receive Client close_notify",
2327
                               [&](Test::Result& result) {
1✔
2328
                                  result.require("ctx is available", ctx != nullptr);
1✔
2329
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2330

2331
                                  ctx->check_callback_invocations(
4✔
2332
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2333

2334
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2335
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
2336
                                  result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2337
                               }),
1✔
2338

2339
            Botan_Tests::CHECK("Expect Server close_notify",
2340
                               [&](Test::Result& result) {
1✔
2341
                                  result.require("ctx is available", ctx != nullptr);
2✔
2342
                                  ctx->server.close();
1✔
2343

2344
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2345
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2346
                                  result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2347
                                  result.test_eq("Server's close notify",
2✔
2348
                                                 ctx->pull_send_buffer(),
2✔
2349
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2350
                               }),
1✔
2351

2352
         };
6✔
2353
      }
1✔
2354

2355
      std::vector<Test::Result> middlebox_compatibility(const VarMap& vars) override {
1✔
2356
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>("");
1✔
2357

2358
         // 32 - for server hello random
2359
         // 32 - for KeyShare (eph. x25519 pair)
2360
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2361

2362
         std::unique_ptr<Server_Context> ctx;
1✔
2363

2364
         return {
1✔
2365
            Botan_Tests::CHECK("Receive Client Hello",
2366
                               [&](Test::Result& result) {
1✔
2367
                                  ctx = std::make_unique<Server_Context>(
2✔
2368
                                     std::move(rng),
1✔
2369
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_compat_server"),
1✔
2370
                                     vars.get_req_u64("CurrentTimestamp"),
3✔
2371
                                     sort_rfc8448_extensions,
2372
                                     make_mock_signatures(vars));
3✔
2373
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
2374

2375
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2376

2377
                                  ctx->check_callback_invocations(result,
16✔
2378
                                                                  "client hello received",
2379
                                                                  {"tls_emit_data",
2380
                                                                   "tls_examine_extensions_client_hello",
2381
                                                                   "tls_modify_extensions_server_hello",
2382
                                                                   "tls_modify_extensions_encrypted_extensions",
2383
                                                                   "tls_modify_extensions_certificate",
2384
                                                                   "tls_sign_message",
2385
                                                                   "tls_generate_ephemeral_key",
2386
                                                                   "tls_ephemeral_key_agreement",
2387
                                                                   "tls_inspect_handshake_msg_client_hello",
2388
                                                                   "tls_inspect_handshake_msg_server_hello",
2389
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
2390
                                                                   "tls_inspect_handshake_msg_certificate",
2391
                                                                   "tls_inspect_handshake_msg_certificate_verify",
2392
                                                                   "tls_inspect_handshake_msg_finished"});
2393
                               }),
1✔
2394

2395
            Botan_Tests::CHECK("Verify server's generated handshake messages",
2396
                               [&](Test::Result& result) {
1✔
2397
                                  result.require("ctx is available", ctx != nullptr);
1✔
2398
                                  const auto& msgs = ctx->observed_handshake_messages();
1✔
2399

2400
                                  result.test_eq("Server Hello",
2✔
2401
                                                 msgs.at("server_hello")[0],
2✔
2402
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
2403
                                  result.test_eq("Encrypted Extensions",
3✔
2404
                                                 msgs.at("encrypted_extensions")[0],
2✔
2405
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2406
                                  result.test_eq("Certificate",
3✔
2407
                                                 msgs.at("certificate")[0],
2✔
2408
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
2409
                                  result.test_eq(
3✔
2410
                                     "CertificateVerify",
2411
                                     msgs.at("certificate_verify")[0],
2✔
2412
                                     strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
2413
                                  result.test_eq("Finished",
3✔
2414
                                                 msgs.at("finished")[0],
2✔
2415
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2416

2417
                                  // Those records contain the required Change Cipher Spec message the server must produce for compatibility mode compliance
2418
                                  result.test_eq("Server's entire first flight",
3✔
2419
                                                 ctx->pull_send_buffer(),
2✔
2420
                                                 concat(vars.get_req_bin("Record_ServerHello"),
5✔
2421
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2422

2423
                                  result.confirm("Server could now send application data", ctx->server.is_active());
2✔
2424
                                  result.confirm("handshake is not yet complete",
3✔
2425
                                                 !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2426
                               }),
1✔
2427

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

2433
                                  ctx->check_callback_invocations(result,
6✔
2434
                                                                  "client finished received",
2435
                                                                  {"tls_inspect_handshake_msg_finished",
2436
                                                                   "tls_current_timestamp",
2437
                                                                   "tls_session_established",
2438
                                                                   "tls_session_activated"});
2439

2440
                                  result.confirm("TLS handshake fully finished", ctx->server.is_active());
2✔
2441
                                  result.confirm("handshake is complete", ctx->server.is_handshake_complete());
2✔
2442
                               }),
1✔
2443

2444
            Botan_Tests::CHECK("Receive Client close_notify",
2445
                               [&](Test::Result& result) {
1✔
2446
                                  result.require("ctx is available", ctx != nullptr);
1✔
2447
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2448

2449
                                  ctx->check_callback_invocations(
4✔
2450
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2451

2452
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2453
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
2454
                                  result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2455
                               }),
1✔
2456

2457
            Botan_Tests::CHECK("Expect Server close_notify",
2458
                               [&](Test::Result& result) {
1✔
2459
                                  result.require("ctx is available", ctx != nullptr);
2✔
2460
                                  ctx->server.close();
1✔
2461

2462
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2463
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2464
                                  result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2465
                                  result.test_eq("Server's close notify",
2✔
2466
                                                 ctx->pull_send_buffer(),
2✔
2467
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2468
                               }),
1✔
2469

2470
         };
6✔
2471
      }
1✔
2472

2473
      std::vector<Test::Result> externally_provided_psk_with_ephemeral_key(const VarMap& vars) override {
1✔
2474
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>("");
1✔
2475

2476
         // 32 - for server hello random
2477
         // 32 - for KeyShare (eph. x25519 key pair)
2478
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2479

2480
         std::unique_ptr<Server_Context> ctx;
1✔
2481

2482
         return {
1✔
2483
            Botan_Tests::CHECK("Send Client Hello",
2484
                               [&](Test::Result& result) {
1✔
2485
                                  auto sort_our_extensions = [&](Botan::TLS::Extensions& exts,
3✔
2486
                                                                 Botan::TLS::Connection_Side /* side */,
2487
                                                                 Botan::TLS::Handshake_Type type) {
2488
                                     // This is the order of extensions when we first introduced the PSK
2489
                                     // implementation and generated the transcript. To stay compatible
2490
                                     // with the now hard-coded transcript, we pin the extension order.
2491
                                     if(type == Botan::TLS::Handshake_Type::EncryptedExtensions) {
2✔
2492
                                        sort_extensions(exts,
2✔
2493
                                                        {
2494
                                                           Botan::TLS::Extension_Code::SupportedGroups,
2495
                                                           Botan::TLS::Extension_Code::RecordSizeLimit,
2496
                                                           Botan::TLS::Extension_Code::ServerNameIndication,
2497
                                                        });
2498
                                     } else if(type == Botan::TLS::Handshake_Type::ServerHello) {
1✔
2499
                                        sort_extensions(exts,
2✔
2500
                                                        {
2501
                                                           Botan::TLS::Extension_Code::SupportedVersions,
2502
                                                           Botan::TLS::Extension_Code::KeyShare,
2503
                                                           Botan::TLS::Extension_Code::PresharedKey,
2504
                                                        });
2505
                                     }
2506
                                  };
2✔
2507

2508
                                  ctx = std::make_unique<Server_Context>(
2✔
2509
                                     std::move(rng),
1✔
2510
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_psk_dhe", false /* no rfc8448 */),
1✔
2511
                                     vars.get_req_u64("CurrentTimestamp"),
4✔
2512
                                     sort_our_extensions,
2513
                                     make_mock_signatures(vars),
1✔
2514
                                     false,
1✔
2515
                                     std::nullopt,
2516
                                     ExternalPSK(vars.get_req_str("PskIdentity"),
2✔
2517
                                                 vars.get_req_str("PskPRF"),
2✔
2518
                                                 lock(vars.get_req_bin("PskSecret"))));
5✔
2519
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
2520

2521
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2522

2523
                                  ctx->check_callback_invocations(result,
12✔
2524
                                                                  "client hello received",
2525
                                                                  {"tls_emit_data",
2526
                                                                   "tls_examine_extensions_client_hello",
2527
                                                                   "tls_modify_extensions_server_hello",
2528
                                                                   "tls_modify_extensions_encrypted_extensions",
2529
                                                                   "tls_generate_ephemeral_key",
2530
                                                                   "tls_ephemeral_key_agreement",
2531
                                                                   "tls_inspect_handshake_msg_client_hello",
2532
                                                                   "tls_inspect_handshake_msg_server_hello",
2533
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
2534
                                                                   "tls_inspect_handshake_msg_finished"});
2535
                               }),
1✔
2536

2537
            Botan_Tests::CHECK("Verify generated messages in server's first flight",
2538
                               [&](Test::Result& result) {
1✔
2539
                                  result.require("ctx is available", ctx != nullptr);
1✔
2540
                                  const auto& msgs = ctx->observed_handshake_messages();
1✔
2541

2542
                                  result.test_eq("Server Hello",
2✔
2543
                                                 msgs.at("server_hello")[0],
2✔
2544
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
2545
                                  result.test_eq("Encrypted Extensions",
3✔
2546
                                                 msgs.at("encrypted_extensions")[0],
2✔
2547
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2548
                                  result.test_eq("Server Finished",
3✔
2549
                                                 msgs.at("finished")[0],
2✔
2550
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2551

2552
                                  result.test_eq("Server's entire first flight",
3✔
2553
                                                 ctx->pull_send_buffer(),
2✔
2554
                                                 concat(vars.get_req_bin("Record_ServerHello"),
5✔
2555
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2556

2557
                                  result.confirm("Server can now send application data", ctx->server.is_active());
2✔
2558
                                  result.confirm("handshake is not yet complete",
3✔
2559
                                                 !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2560
                               }),
1✔
2561

2562
            Botan_Tests::CHECK("Send Client Finished",
2563
                               [&](Test::Result& result) {
1✔
2564
                                  result.require("ctx is available", ctx != nullptr);
2✔
2565
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2566
                                  result.require("PSK negotiated",
3✔
2567
                                                 ctx->psk_identity_negotiated() == vars.get_req_str("PskIdentity"));
2✔
2568

2569
                                  ctx->check_callback_invocations(result,
6✔
2570
                                                                  "client finished received",
2571
                                                                  {"tls_inspect_handshake_msg_finished",
2572
                                                                   "tls_current_timestamp",
2573
                                                                   "tls_session_established",
2574
                                                                   "tls_session_activated"});
2575
                               }),
1✔
2576

2577
            Botan_Tests::CHECK(
2578
               "Exchange Application Data",
2579
               [&](Test::Result& result) {
1✔
2580
                  result.require("ctx is available", ctx != nullptr);
2✔
2581
                  ctx->server.received_data(vars.get_req_bin("Record_Client_AppData"));
3✔
2582
                  ctx->check_callback_invocations(result, "application data received", {"tls_record_received"});
3✔
2583

2584
                  const auto rcvd = ctx->pull_receive_buffer();
1✔
2585
                  result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Client_AppData"));
3✔
2586
                  result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
1✔
2587

2588
                  ctx->send(vars.get_req_bin("Server_AppData"));
3✔
2589
                  ctx->check_callback_invocations(result, "application data sent", {"tls_emit_data"});
3✔
2590
                  result.test_eq("correct server application data",
3✔
2591
                                 ctx->pull_send_buffer(),
2✔
2592
                                 vars.get_req_bin("Record_Server_AppData"));
3✔
2593
               }),
1✔
2594

2595
            Botan_Tests::CHECK("Terminate Connection",
2596
                               [&](Test::Result& result) {
1✔
2597
                                  result.require("ctx is available", ctx != nullptr);
2✔
2598
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2599

2600
                                  ctx->check_callback_invocations(
4✔
2601
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2602

2603
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2604
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
2605
                                  result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2606

2607
                                  ctx->server.close();
1✔
2608

2609
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2610
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2611
                                  result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2612
                                  result.test_eq("Server's close notify",
3✔
2613
                                                 ctx->pull_send_buffer(),
2✔
2614
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2615
                               }),
1✔
2616
         };
6✔
2617
      }
1✔
2618

2619
      std::vector<Test::Result> raw_public_key_with_client_authentication(const VarMap& vars) override {
1✔
2620
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>("");
1✔
2621

2622
         // 32 - for server hello random
2623
         // 32 - for KeyShare (eph. x25519 key pair)
2624
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2625

2626
         auto sort_our_extensions =
1✔
2627
            [&](Botan::TLS::Extensions& exts, Botan::TLS::Connection_Side /* side */, Botan::TLS::Handshake_Type type) {
3✔
2628
               // This is the order of extensions when we first introduced the raw
2629
               // public key authentication implementation and generated the transcript.
2630
               // To stay compatible with the now hard-coded transcript, we pin the
2631
               // extension order.
2632
               if(type == Botan::TLS::Handshake_Type::EncryptedExtensions) {
3✔
2633
                  sort_extensions(exts,
2✔
2634
                                  {
2635
                                     Botan::TLS::Extension_Code::ClientCertificateType,
2636
                                     Botan::TLS::Extension_Code::ServerCertificateType,
2637
                                     Botan::TLS::Extension_Code::SupportedGroups,
2638
                                     Botan::TLS::Extension_Code::RecordSizeLimit,
2639
                                     Botan::TLS::Extension_Code::ServerNameIndication,
2640
                                  });
2641
               } else if(type == Botan::TLS::Handshake_Type::ServerHello) {
2✔
2642
                  sort_extensions(exts,
2✔
2643
                                  {
2644
                                     Botan::TLS::Extension_Code::KeyShare,
2645
                                     Botan::TLS::Extension_Code::SupportedVersions,
2646
                                  });
2647
               }
2648
            };
3✔
2649

2650
         std::unique_ptr<Server_Context> ctx;
1✔
2651

2652
         return {
1✔
2653
            Botan_Tests::CHECK("Receive Client Hello",
2654
                               [&](Test::Result& result) {
1✔
2655
                                  ctx = std::make_unique<Server_Context>(
2✔
2656
                                     std::move(rng),
1✔
2657
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_rawpubkey"),
1✔
2658
                                     vars.get_req_u64("CurrentTimestamp"),
3✔
2659
                                     sort_our_extensions,
1✔
2660
                                     make_mock_signatures(vars));
3✔
2661
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
2662

2663
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2664

2665
                                  ctx->check_callback_invocations(result,
17✔
2666
                                                                  "client hello received",
2667
                                                                  {"tls_emit_data",
2668
                                                                   "tls_examine_extensions_client_hello",
2669
                                                                   "tls_modify_extensions_server_hello",
2670
                                                                   "tls_modify_extensions_encrypted_extensions",
2671
                                                                   "tls_modify_extensions_certificate",
2672
                                                                   "tls_sign_message",
2673
                                                                   "tls_generate_ephemeral_key",
2674
                                                                   "tls_ephemeral_key_agreement",
2675
                                                                   "tls_inspect_handshake_msg_client_hello",
2676
                                                                   "tls_inspect_handshake_msg_server_hello",
2677
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
2678
                                                                   "tls_inspect_handshake_msg_certificate_request",
2679
                                                                   "tls_inspect_handshake_msg_certificate",
2680
                                                                   "tls_inspect_handshake_msg_certificate_verify",
2681
                                                                   "tls_inspect_handshake_msg_finished"});
2682
                               }),
1✔
2683

2684
            Botan_Tests::CHECK(
2685
               "Verify server's generated handshake messages",
2686
               [&](Test::Result& result) {
1✔
2687
                  result.require("ctx is available", ctx != nullptr);
1✔
2688
                  const auto& msgs = ctx->observed_handshake_messages();
1✔
2689

2690
                  result.test_eq("Server Hello",
2✔
2691
                                 msgs.at("server_hello")[0],
2✔
2692
                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
2693
                  result.test_eq("Encrypted Extensions",
3✔
2694
                                 msgs.at("encrypted_extensions")[0],
2✔
2695
                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2696
                  result.test_eq("Certificate Request",
3✔
2697
                                 msgs.at("certificate_request")[0],
2✔
2698
                                 strip_message_header(vars.get_opt_bin("Message_CertificateRequest")));
3✔
2699
                  result.test_eq("Certificate",
3✔
2700
                                 msgs.at("certificate")[0],
2✔
2701
                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
2702
                  result.test_eq("CertificateVerify",
3✔
2703
                                 msgs.at("certificate_verify")[0],
2✔
2704
                                 strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
2705
                  result.test_eq("Finished",
3✔
2706
                                 msgs.at("finished")[0],
2✔
2707
                                 strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2708

2709
                  result.test_eq("Server's entire first flight",
3✔
2710
                                 ctx->pull_send_buffer(),
2✔
2711
                                 concat(vars.get_req_bin("Record_ServerHello"),
5✔
2712
                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2713

2714
                  result.confirm("Not yet aware of client's cert chain", ctx->server.peer_cert_chain().empty());
3✔
2715
                  result.confirm("Server could now send application data", ctx->server.is_active());
2✔
2716
                  result.confirm("handshake is not yet complete",
3✔
2717
                                 !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2718
               }),
1✔
2719

2720
            Botan_Tests::CHECK("Receive Client's second flight",
2721
                               [&](Test::Result& result) {
1✔
2722
                                  result.require("ctx is available", ctx != nullptr);
1✔
2723
                                  // This encrypted message contains the following messages:
2724
                                  // * client's Certificate message
2725
                                  // * client's Certificate_Verify message
2726
                                  // * client's Finished message
2727
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2728

2729
                                  ctx->check_callback_invocations(result,
11✔
2730
                                                                  "client finished received",
2731
                                                                  {"tls_inspect_handshake_msg_certificate",
2732
                                                                   "tls_inspect_handshake_msg_certificate_verify",
2733
                                                                   "tls_inspect_handshake_msg_finished",
2734
                                                                   "tls_examine_extensions_certificate",
2735
                                                                   "tls_verify_raw_public_key",
2736
                                                                   "tls_verify_message",
2737
                                                                   "tls_current_timestamp",
2738
                                                                   "tls_session_established",
2739
                                                                   "tls_session_activated"});
2740

2741
                                  const auto raw_pk = ctx->server.peer_raw_public_key();
1✔
2742
                                  result.confirm("Received client's raw public key",
2✔
2743
                                                 raw_pk && raw_pk->fingerprint_public() ==
3✔
2744
                                                              client_raw_public_key_pair()->fingerprint_public());
3✔
2745

2746
                                  result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2747
                                  result.confirm("handshake is complete", ctx->server.is_handshake_complete());
3✔
2748
                               }),
1✔
2749

2750
            Botan_Tests::CHECK("Receive Client close_notify",
2751
                               [&](Test::Result& result) {
1✔
2752
                                  result.require("ctx is available", ctx != nullptr);
1✔
2753
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2754

2755
                                  ctx->check_callback_invocations(
4✔
2756
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2757

2758
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2759
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
2760
                                  result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2761
                               }),
1✔
2762

2763
            Botan_Tests::CHECK("Expect Server close_notify",
2764
                               [&](Test::Result& result) {
1✔
2765
                                  result.require("ctx is available", ctx != nullptr);
2✔
2766
                                  ctx->server.close();
1✔
2767

2768
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2769
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2770
                                  result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2771
                                  result.test_eq("Server's close notify",
2✔
2772
                                                 ctx->pull_send_buffer(),
2✔
2773
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2774
                               }),
1✔
2775
         };
6✔
2776
      }
1✔
2777
};
2778

2779
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_client", Test_TLS_RFC8448_Client);
2780
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_server", Test_TLS_RFC8448_Server);
2781

2782
#endif
2783

2784
}  // 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