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

randombit / botan / 5784172412

07 Aug 2023 10:48AM UTC coverage: 91.688% (+0.004%) from 91.684%
5784172412

push

github

web-flow
Merge pull request #3618 from Rohde-Schwarz/tls13/psk

[TLS 1.3] PSK Support

78518 of 85636 relevant lines covered (91.69%)

12136131.94 hits per line

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

97.05
/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_CURVE_25519) && defined(BOTAN_HAS_SHA2_32) &&                 \
18
   defined(BOTAN_HAS_SHA2_64) && 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/internal/fmt.h>
37
   #include <botan/internal/stl_util.h>
38
#endif
39

40
namespace Botan_Tests {
41

42
#if defined(BOTAN_CAN_RUN_TEST_TLS_RFC8448)
43

44
namespace {
45

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

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

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

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

74
/**
75
* Simple version of the Padding extension (RFC 7685) to reproduce the
76
* 2nd Client_Hello in RFC8448 Section 5 (HelloRetryRequest)
77
*/
78
class Padding final : public Botan::TLS::Extension {
79
   public:
80
      static Botan::TLS::Extension_Code static_type() { return Botan::TLS::Extension_Code(21); }
81

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

84
      explicit Padding(const size_t padding_bytes) : m_padding_bytes(padding_bytes) {}
2✔
85

86
      std::vector<uint8_t> serialize(Botan::TLS::Connection_Side) const override {
5✔
87
         return std::vector<uint8_t>(m_padding_bytes, 0x00);
5✔
88
      }
89

90
      bool empty() const override { return m_padding_bytes == 0; }
5✔
91

92
   private:
93
      size_t m_padding_bytes;
94
};
95

96
using namespace Botan;
97
using namespace Botan::TLS;
98

99
std::chrono::system_clock::time_point from_milliseconds_since_epoch(uint64_t msecs) {
12✔
100
   const int64_t secs_since_epoch = msecs / 1000;
12✔
101
   const uint32_t additional_millis = msecs % 1000;
12✔
102

103
   BOTAN_ASSERT_NOMSG(secs_since_epoch <= std::numeric_limits<time_t>::max());
12✔
104
   return std::chrono::system_clock::from_time_t(static_cast<time_t>(secs_since_epoch)) +
12✔
105
          std::chrono::milliseconds(additional_millis);
12✔
106
}
107

108
using Modify_Exts_Fn =
109
   std::function<void(Botan::TLS::Extensions&, Botan::TLS::Connection_Side, Botan::TLS::Handshake_Type)>;
110

111
/**
112
 * We cannot actually reproduce the signatures stated in RFC 8448 as their
113
 * signature scheme is probabilistic and we're lacking the correct RNG
114
 * input. Hence, signatures are know beforehand and just reproduced by the
115
 * TLS callback when requested.
116
 */
117
struct MockSignature {
9✔
118
      std::vector<uint8_t> message_to_sign;
119
      std::vector<uint8_t> signature_to_produce;
120
};
121

122
/**
123
 * Subclass of the Botan::TLS::Callbacks instrumenting all available callbacks.
124
 * The invocation counts can be checked in the integration tests to make sure
125
 * all expected callbacks are hit. Furthermore collects the received application
126
 * data and sent record bytes for further inspection by the test cases.
127
 */
128
class Test_TLS_13_Callbacks : public Botan::TLS::Callbacks {
129
   public:
130
      Test_TLS_13_Callbacks(Modify_Exts_Fn modify_exts_cb,
12✔
131
                            std::vector<MockSignature> mock_signatures,
132
                            uint64_t timestamp) :
12✔
133
            session_activated_called(false),
12✔
134
            m_modify_exts(std::move(modify_exts_cb)),
12✔
135
            m_mock_signatures(std::move(mock_signatures)),
12✔
136
            m_timestamp(from_milliseconds_since_epoch(timestamp)) {}
12✔
137

138
      void tls_emit_data(std::span<const uint8_t> data) override {
41✔
139
         count_callback_invocation("tls_emit_data");
41✔
140
         send_buffer.insert(send_buffer.end(), data.begin(), data.end());
41✔
141
      }
41✔
142

143
      void tls_record_received(uint64_t seq_no, std::span<const uint8_t> data) override {
4✔
144
         count_callback_invocation("tls_record_received");
4✔
145
         received_seq_no = seq_no;
4✔
146
         receive_buffer.insert(receive_buffer.end(), data.begin(), data.end());
4✔
147
      }
4✔
148

149
      void tls_alert(Botan::TLS::Alert alert) override {
10✔
150
         count_callback_invocation("tls_alert");
10✔
151
         BOTAN_UNUSED(alert);
10✔
152
         // handle a tls alert received from the tls server
153
      }
10✔
154

155
      bool tls_peer_closed_connection() override {
10✔
156
         count_callback_invocation("tls_peer_closed_connection");
20✔
157
         // we want to handle the closure ourselves
158
         return false;
10✔
159
      }
160

161
      void tls_session_established(const Botan::TLS::Session_Summary& summary) override {
10✔
162
         if(summary.psk_used()) {
10✔
163
            negotiated_psk_identity = summary.external_psk_identity().value();
2✔
164
         }
165
         count_callback_invocation("tls_session_established");
10✔
166
      }
10✔
167

168
      void tls_session_activated() override {
10✔
169
         count_callback_invocation("tls_session_activated");
10✔
170
         session_activated_called = true;
10✔
171
      }
10✔
172

173
      bool tls_should_persist_resumption_information(const Session&) override {
2✔
174
         count_callback_invocation("tls_should_persist_resumption_information");
2✔
175
         return true;  // should always store the session
2✔
176
      }
177

178
      void tls_verify_cert_chain(const std::vector<Botan::X509_Certificate>& cert_chain,
5✔
179
                                 const std::vector<std::optional<Botan::OCSP::Response>>&,
180
                                 const std::vector<Botan::Certificate_Store*>&,
181
                                 Botan::Usage_Type,
182
                                 std::string_view,
183
                                 const Botan::TLS::Policy&) override {
184
         count_callback_invocation("tls_verify_cert_chain");
5✔
185
         certificate_chain = cert_chain;
5✔
186
      }
5✔
187

188
      std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const override {
×
189
         count_callback_invocation("tls_verify_cert_chain");
×
190
         return std::chrono::milliseconds(0);
×
191
      }
192

193
      std::vector<uint8_t> tls_provide_cert_status(const std::vector<X509_Certificate>& chain,
×
194
                                                   const Certificate_Status_Request& csr) override {
195
         count_callback_invocation("tls_provide_cert_status");
×
196
         return Callbacks::tls_provide_cert_status(chain, csr);
×
197
      }
198

199
      std::vector<uint8_t> tls_sign_message(const Private_Key& key,
5✔
200
                                            RandomNumberGenerator& rng,
201
                                            std::string_view padding,
202
                                            Signature_Format format,
203
                                            const std::vector<uint8_t>& msg) override {
204
         BOTAN_UNUSED(key, rng);
5✔
205
         count_callback_invocation("tls_sign_message");
5✔
206

207
         if(key.algo_name() == "RSA") {
5✔
208
            if(format != Signature_Format::Standard) {
4✔
209
               throw Test_Error("TLS implementation selected unexpected signature format for RSA");
×
210
            }
211

212
            if(padding != "PSSR(SHA-256,MGF1,32)") {
8✔
213
               throw Test_Error("TLS implementation selected unexpected padding for RSA: " + std::string(padding));
×
214
            }
215
         } else if(key.algo_name() == "ECDSA") {
1✔
216
            if(format != Signature_Format::DerSequence) {
1✔
217
               throw Test_Error("TLS implementation selected unexpected signature format for ECDSA");
×
218
            }
219

220
            if(padding != "SHA-256") {
2✔
221
               throw Test_Error("TLS implementation selected unexpected padding for ECDSA: " + std::string(padding));
×
222
            }
223
         } else {
224
            throw Test_Error("TLS implementation trying to sign with unexpected algorithm (" + key.algo_name() + ")");
×
225
         }
226

227
         for(const auto& mock : m_mock_signatures) {
6✔
228
            if(mock.message_to_sign == msg) {
6✔
229
               return mock.signature_to_produce;
5✔
230
            }
231
         }
232

233
         throw Test_Error("TLS implementation produced an unexpected message to be signed: " + Botan::hex_encode(msg));
×
234
      }
235

236
      bool tls_verify_message(const Public_Key& key,
5✔
237
                              std::string_view padding,
238
                              Signature_Format format,
239
                              const std::vector<uint8_t>& msg,
240
                              const std::vector<uint8_t>& sig) override {
241
         count_callback_invocation("tls_verify_message");
5✔
242
         return Callbacks::tls_verify_message(key, padding, format, msg, sig);
5✔
243
      }
244

245
      std::unique_ptr<PK_Key_Agreement_Key> tls_generate_ephemeral_key(
13✔
246
         const std::variant<TLS::Group_Params, DL_Group>& group, RandomNumberGenerator& rng) override {
247
         count_callback_invocation("tls_generate_ephemeral_key");
13✔
248
         return Callbacks::tls_generate_ephemeral_key(group, rng);
13✔
249
      }
250

251
      secure_vector<uint8_t> tls_ephemeral_key_agreement(const std::variant<TLS::Group_Params, DL_Group>& group,
11✔
252
                                                         const PK_Key_Agreement_Key& private_key,
253
                                                         const std::vector<uint8_t>& public_value,
254
                                                         RandomNumberGenerator& rng,
255
                                                         const Policy& policy) override {
256
         count_callback_invocation("tls_ephemeral_key_agreement");
11✔
257
         return Callbacks::tls_ephemeral_key_agreement(group, private_key, public_value, rng, policy);
11✔
258
      }
259

260
      void tls_inspect_handshake_msg(const Handshake_Message& message) override {
82✔
261
         count_callback_invocation("tls_inspect_handshake_msg_" + message.type_string());
164✔
262

263
         try {
82✔
264
            auto serialized_message = message.serialize();
82✔
265

266
            serialized_messages.try_emplace(message.type_string())
166✔
267
               .first->second.emplace_back(std::move(serialized_message));
82✔
268
         } catch(const Not_Implemented&) {
82✔
269
            // TODO: Once the server implementation is finished, this crutch
270
            //       can likely be removed, as all message types will have a
271
            //       serialization method with actual business logic. :o)
272
         }
×
273

274
         return Callbacks::tls_inspect_handshake_msg(message);
82✔
275
      }
276

277
      std::string tls_server_choose_app_protocol(const std::vector<std::string>& client_protos) override {
×
278
         count_callback_invocation("tls_server_choose_app_protocol");
×
279
         return Callbacks::tls_server_choose_app_protocol(client_protos);
×
280
      }
281

282
      void tls_modify_extensions(Botan::TLS::Extensions& exts,
26✔
283
                                 Botan::TLS::Connection_Side side,
284
                                 Botan::TLS::Handshake_Type which_message) override {
285
         count_callback_invocation(std::string("tls_modify_extensions_") + handshake_type_to_string(which_message));
52✔
286
         m_modify_exts(exts, side, which_message);
26✔
287
         Callbacks::tls_modify_extensions(exts, side, which_message);
26✔
288
      }
26✔
289

290
      void tls_examine_extensions(const Botan::TLS::Extensions& extn,
25✔
291
                                  Connection_Side which_side,
292
                                  Botan::TLS::Handshake_Type which_message) override {
293
         count_callback_invocation(std::string("tls_examine_extensions_") + handshake_type_to_string(which_message));
50✔
294
         return Callbacks::tls_examine_extensions(extn, which_side, which_message);
25✔
295
      }
296

297
      std::string tls_peer_network_identity() override {
×
298
         count_callback_invocation("tls_peer_network_identity");
×
299
         return Callbacks::tls_peer_network_identity();
×
300
      }
301

302
      std::chrono::system_clock::time_point tls_current_timestamp() override {
20✔
303
         count_callback_invocation("tls_current_timestamp");
20✔
304
         return m_timestamp;
20✔
305
      }
306

307
      std::vector<uint8_t> pull_send_buffer() { return std::exchange(send_buffer, std::vector<uint8_t>()); }
34✔
308

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

311
      uint64_t last_received_seq_no() const { return received_seq_no; }
4✔
312

313
      const std::map<std::string, unsigned int>& callback_invocations() const { return m_callback_invocations; }
52✔
314

315
      void reset_callback_invocation_counters() { m_callback_invocations.clear(); }
52✔
316

317
   private:
318
      void count_callback_invocation(const std::string& callback_name) const {
279✔
319
         if(!m_callback_invocations.contains(callback_name)) {
279✔
320
            m_callback_invocations[callback_name] = 0;
264✔
321
         }
322

323
         m_callback_invocations[callback_name]++;
279✔
324
      }
279✔
325

326
   public:
327
      bool session_activated_called;                           // NOLINT(*-non-private-member-variables-in-classes)
328
      std::vector<Botan::X509_Certificate> certificate_chain;  // NOLINT(*-non-private-member-variables-in-classes)
329
      std::string negotiated_psk_identity;                     // NOLINT(*-non-private-member-variables-in-classes)
330
      std::map<std::string, std::vector<std::vector<uint8_t>>>
331
         serialized_messages;  // NOLINT(*-non-private-member-variables-in-classes)
332

333
   private:
334
      std::vector<uint8_t> send_buffer;
335
      std::vector<uint8_t> receive_buffer;
336
      uint64_t received_seq_no;
337
      Modify_Exts_Fn m_modify_exts;
338
      std::vector<MockSignature> m_mock_signatures;
339
      std::chrono::system_clock::time_point m_timestamp;
340

341
      mutable std::map<std::string, unsigned int> m_callback_invocations;
342
};
343

344
class Test_Credentials : public Botan::Credentials_Manager {
345
   public:
346
      explicit Test_Credentials(bool use_alternative_server_certificate, std::optional<ExternalPSK> external_psk) :
12✔
347
            m_alternative_server_certificate(use_alternative_server_certificate),
12✔
348
            m_external_psk(std::move(external_psk)) {
14✔
349
         Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/server_key.pem"));
24✔
350
         m_server_private_key.reset(Botan::PKCS8::load_key(in).release());
12✔
351

352
         // RFC 8448 does not actually provide these keys. Hence we generate one on the
353
         // fly as a stand-in. Instead of actually using it, the signatures generated
354
         // by this private key must be hard-coded in `Callbacks::sign_message()`; see
355
         // `MockSignature_Fn` for more details.
356
         m_bogus_alternative_server_private_key.reset(create_private_key("ECDSA", Test::rng(), "secp256r1").release());
12✔
357

358
         m_client_private_key.reset(create_private_key("RSA", Test::rng(), "1024").release());
24✔
359
      }
12✔
360

361
      std::vector<Botan::X509_Certificate> cert_chain(const std::vector<std::string>& cert_key_types,
5✔
362
                                                      const std::vector<AlgorithmIdentifier>& cert_signature_schemes,
363
                                                      const std::string& type,
364
                                                      const std::string& context) override {
365
         BOTAN_UNUSED(cert_key_types, cert_signature_schemes, context);
5✔
366
         return {(type == "tls-client")
5✔
367
                    ? client_certificate()
368
                    : ((m_alternative_server_certificate) ? alternative_server_certificate() : server_certificate())};
10✔
369
      }
370

371
      std::shared_ptr<Botan::Private_Key> private_key_for(const Botan::X509_Certificate& cert,
5✔
372
                                                          const std::string& type,
373
                                                          const std::string& context) override {
374
         BOTAN_UNUSED(cert, context);
5✔
375

376
         if(type == "tls-client") {
5✔
377
            return m_client_private_key;
1✔
378
         }
379

380
         if(m_alternative_server_certificate) {
4✔
381
            return m_bogus_alternative_server_private_key;
1✔
382
         }
383

384
         return m_server_private_key;
3✔
385
      }
386

387
      std::vector<TLS::ExternalPSK> find_preshared_keys(std::string_view /* host */,
7✔
388
                                                        TLS::Connection_Side /* whoami */,
389
                                                        const std::vector<std::string>& identities,
390
                                                        const std::optional<std::string>& prf) override {
391
         if(!m_external_psk.has_value()) {
7✔
392
            return {};
5✔
393
         }
394

395
         ExternalPSK& epsk = m_external_psk.value();
2✔
396
         const auto found = std::find(identities.begin(), identities.end(), epsk.identity());
2✔
397
         if(!identities.empty() && found == identities.end()) {
2✔
398
            return {};
×
399
         }
400

401
         if(prf && prf != epsk.prf_algo()) {
2✔
402
            return {};
×
403
         }
404

405
         // ExternalPSK has a deleted copy constructor. We need to do some gymnastics
406
         // to copy it and leave the data in m_external_psk intact
407
         const auto secret = epsk.extract_master_secret();
2✔
408
         m_external_psk = ExternalPSK(epsk.identity(), epsk.prf_algo(), secret);
2✔
409
         std::vector<ExternalPSK> psks;
2✔
410
         psks.emplace_back(epsk.identity(), epsk.prf_algo(), secret);
2✔
411
         return psks;
2✔
412
      }
9✔
413

414
   private:
415
      bool m_alternative_server_certificate;
416
      std::optional<ExternalPSK> m_external_psk;
417
      std::shared_ptr<Private_Key> m_client_private_key;
418
      std::shared_ptr<Private_Key> m_bogus_alternative_server_private_key;
419
      std::shared_ptr<Private_Key> m_server_private_key;
420
};
421

422
class RFC8448_Text_Policy : public Botan::TLS::Text_Policy {
12✔
423
   private:
424
      Botan::TLS::Text_Policy read_policy(const std::string& policy_file) {
12✔
425
         const std::string fspath = Test::data_file("tls-policy/" + policy_file + ".txt");
24✔
426

427
         std::ifstream is(fspath.c_str());
12✔
428
         if(!is.good()) {
12✔
429
            throw Test_Error("Missing policy file " + fspath);
×
430
         }
431

432
         return Botan::TLS::Text_Policy(is);
12✔
433
      }
24✔
434

435
   public:
436
      RFC8448_Text_Policy(const std::string& policy_file, bool rfc8448 = true) :
12✔
437
            Botan::TLS::Text_Policy(read_policy(policy_file)), m_rfc8448(rfc8448) {}
12✔
438

439
      std::vector<Botan::TLS::Signature_Scheme> allowed_signature_schemes() const override {
12✔
440
         if(!m_rfc8448) {
12✔
441
            return Botan::TLS::Text_Policy::allowed_signature_schemes();
1✔
442
         }
443

444
         // We extend the allowed signature schemes with algorithms that we don't
445
         // actually support. The nature of the RFC 8448 test forces us to generate
446
         // bit-compatible TLS messages. Unfortunately, the test data offers all
447
         // those algorithms in its Client Hellos.
448
         return {
11✔
449
            Botan::TLS::Signature_Scheme::ECDSA_SHA256,
450
            Botan::TLS::Signature_Scheme::ECDSA_SHA384,
451
            Botan::TLS::Signature_Scheme::ECDSA_SHA512,
452
            Botan::TLS::Signature_Scheme::ECDSA_SHA1,  // not actually supported
453
            Botan::TLS::Signature_Scheme::RSA_PSS_SHA256,
454
            Botan::TLS::Signature_Scheme::RSA_PSS_SHA384,
455
            Botan::TLS::Signature_Scheme::RSA_PSS_SHA512,
456
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA256,
457
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA384,
458
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA512,
459
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA1,  // not actually supported
460
            Botan::TLS::Signature_Scheme(0x0402),          // DSA_SHA256, not actually supported
461
            Botan::TLS::Signature_Scheme(0x0502),          // DSA_SHA384, not actually supported
462
            Botan::TLS::Signature_Scheme(0x0602),          // DSA_SHA512, not actually supported
463
            Botan::TLS::Signature_Scheme(0x0202),          // DSA_SHA1, not actually supported
464
         };
11✔
465
      }
466

467
      // Overriding the key exchange group selection to favour the server's key
468
      // exchange group preference. This is required to enforce a Hello Retry Request
469
      // when testing RFC 8448 5. from the server side.
470
      Named_Group choose_key_exchange_group(const std::vector<Group_Params>& supported_by_peer,
7✔
471
                                            const std::vector<Group_Params>& offered_by_peer) const override {
472
         BOTAN_UNUSED(offered_by_peer);
7✔
473

474
         const auto supported_by_us = key_exchange_groups();
7✔
475
         const auto selected_group =
7✔
476
            std::find_if(supported_by_us.begin(), supported_by_us.end(), [&](const auto group) {
7✔
477
               return value_exists(supported_by_peer, group);
14✔
478
            });
479

480
         return selected_group != supported_by_us.end() ? *selected_group : Named_Group::NONE;
7✔
481
      }
7✔
482

483
   private:
484
      bool m_rfc8448;
485
};
486

487
/**
488
 * In-Memory Session Manager that stores sessions verbatim, without encryption.
489
 * Therefor it is not dependent on a random number generator and can easily be
490
 * instrumented for test inspection.
491
 */
492
class RFC8448_Session_Manager : public Botan::TLS::Session_Manager {
493
   private:
494
      decltype(auto) find_by_handle(const Session_Handle& handle) {
3✔
495
         return [=](const Session_with_Handle& session) {
30✔
496
            if(session.handle.id().has_value() && handle.id().has_value() &&
4✔
497
               session.handle.id().value() == handle.id().value()) {
2✔
498
               return true;
499
            }
500
            if(session.handle.ticket().has_value() && handle.ticket().has_value() &&
8✔
501
               session.handle.ticket().value() == handle.ticket().value()) {
10✔
502
               return true;
2✔
503
            }
504
            return false;
505
         };
3✔
506
      }
507

508
   public:
509
      RFC8448_Session_Manager() : Session_Manager(Test::rng_as_shared()) {}
24✔
510

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

513
      void store(const Session& session, const Session_Handle& handle) override {
4✔
514
         m_sessions.push_back({session, handle});
4✔
515
      }
4✔
516

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

522
         if(m_sessions.size() != 1) {
1✔
523
            throw Botan_Tests::Test_Error("No mocked session handle available; Test bug?");
×
524
         }
525

526
         const auto& [mocked_session, handle] = m_sessions.front();
1✔
527
         if(mocked_session.master_secret() != session.master_secret()) {
1✔
528
            throw Botan_Tests::Test_Error("Generated session object does not match the expected mock");
×
529
         }
530

531
         return handle;
1✔
532
      }
533

534
      std::optional<Session> retrieve_one(const Session_Handle& handle) override {
2✔
535
         auto itr = std::find_if(m_sessions.begin(), m_sessions.end(), find_by_handle(handle));
2✔
536
         if(itr == m_sessions.end()) {
2✔
537
            return std::nullopt;
1✔
538
         } else {
539
            return itr->session;
3✔
540
         }
541
      }
542

543
      std::vector<Session_with_Handle> find_some(const Server_Information& info, const size_t) override {
6✔
544
         std::vector<Session_with_Handle> found_sessions;
6✔
545
         for(const auto& [session, handle] : m_sessions) {
7✔
546
            if(session.server_info() == info) {
1✔
547
               found_sessions.emplace_back(Session_with_Handle{session, handle});
2✔
548
            }
549
         }
550

551
         return found_sessions;
6✔
552
      }
×
553

554
      size_t remove(const Session_Handle& handle) override {
1✔
555
         // TODO: C++20 allows to simply implement the entire method like:
556
         //
557
         //   return std::erase_if(m_sessions, find_by_handle(handle));
558
         //
559
         // Unfortunately, at the time of this writing Android NDK shipped with
560
         // a std::erase_if that returns void.
561
         auto rm_itr = std::remove_if(m_sessions.begin(), m_sessions.end(), find_by_handle(handle));
1✔
562

563
         const auto elements_being_removed = std::distance(rm_itr, m_sessions.end());
1✔
564
         m_sessions.erase(rm_itr);
1✔
565
         return elements_being_removed;
1✔
566
      }
567

568
      size_t remove_all() override {
×
569
         const auto sessions = m_sessions.size();
×
570
         m_sessions.clear();
×
571
         return sessions;
×
572
      }
573

574
   private:
575
      std::vector<Session_with_Handle> m_sessions;
576
};
577

578
/**
579
 * This steers the TLS client handle and is the central entry point for the
580
 * test cases to interact with the TLS 1.3 implementation.
581
 *
582
 * Note: This class is abstract to be subclassed for both client and server tests.
583
 */
584
class TLS_Context {
585
   protected:
586
      TLS_Context(std::shared_ptr<Botan::RandomNumberGenerator> rng_in,
12✔
587
                  std::shared_ptr<const RFC8448_Text_Policy> policy,
588
                  Modify_Exts_Fn modify_exts_cb,
589
                  std::vector<MockSignature> mock_signatures,
590
                  uint64_t timestamp,
591
                  std::optional<std::pair<Session, Session_Ticket>> session_and_ticket,
592
                  std::optional<ExternalPSK> external_psk,
593
                  bool use_alternative_server_certificate) :
12✔
594
            m_callbacks(std::make_shared<Test_TLS_13_Callbacks>(
12✔
595
               std::move(modify_exts_cb), std::move(mock_signatures), timestamp)),
12✔
596
            m_creds(std::make_shared<Test_Credentials>(use_alternative_server_certificate, std::move(external_psk))),
12✔
597
            m_rng(std::move(rng_in)),
12✔
598
            m_session_mgr(std::make_shared<RFC8448_Session_Manager>()),
599
            m_policy(std::move(policy)) {
24✔
600
         if(session_and_ticket.has_value()) {
12✔
601
            m_session_mgr->store(std::get<Session>(session_and_ticket.value()),
12✔
602
                                 std::get<Session_Ticket>(session_and_ticket.value()));
3✔
603
         }
604
      }
12✔
605

606
   public:
607
      virtual ~TLS_Context() = default;
60✔
608

609
      TLS_Context(TLS_Context&) = delete;
610
      TLS_Context& operator=(const TLS_Context&) = delete;
611

612
      TLS_Context(TLS_Context&&) = delete;
613
      TLS_Context& operator=(TLS_Context&&) = delete;
614

615
      std::vector<uint8_t> pull_send_buffer() { return m_callbacks->pull_send_buffer(); }
34✔
616

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

619
      uint64_t last_received_seq_no() const { return m_callbacks->last_received_seq_no(); }
4✔
620

621
      /**
622
       * Checks that all of the listed callbacks were called at least once, no other
623
       * callbacks were called in addition to the expected ones. After the checks are
624
       * done, the callback invocation counters are reset.
625
       */
626
      void check_callback_invocations(Test::Result& result,
52✔
627
                                      const std::string& context,
628
                                      const std::vector<std::string>& callback_names) {
629
         const auto& invokes = m_callbacks->callback_invocations();
52✔
630
         for(const auto& cbn : callback_names) {
308✔
631
            result.confirm(Botan::fmt("{} was invoked (Context: {})", cbn, context),
1,024✔
632
                           invokes.contains(cbn) && invokes.at(cbn) > 0);
256✔
633
         }
634

635
         for(const auto& invoke : invokes) {
308✔
636
            if(invoke.second == 0) {
256✔
637
               continue;
×
638
            }
639
            result.confirm(
512✔
640
               invoke.first + " was expected (Context: " + context + ")",
512✔
641
               std::find(callback_names.cbegin(), callback_names.cend(), invoke.first) != callback_names.cend());
512✔
642
         }
643

644
         m_callbacks->reset_callback_invocation_counters();
52✔
645
      }
52✔
646

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

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

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

653
      decltype(auto) observed_handshake_messages() const { return m_callbacks->serialized_messages; }
6✔
654

655
      /**
656
       * Send application data through the secure channel
657
       */
658
      virtual void send(const std::vector<uint8_t>& data) = 0;
659

660
   protected:
661
      std::shared_ptr<Test_TLS_13_Callbacks> m_callbacks;  // NOLINT(*-non-private-member-variables-in-classes)
662
      std::shared_ptr<Test_Credentials> m_creds;           // NOLINT(*-non-private-member-variables-in-classes)
663

664
      std::shared_ptr<Botan::RandomNumberGenerator> m_rng;     // NOLINT(*-non-private-member-variables-in-classes)
665
      std::shared_ptr<RFC8448_Session_Manager> m_session_mgr;  // NOLINT(*-non-private-member-variables-in-classes)
666
      std::shared_ptr<const RFC8448_Text_Policy> m_policy;     // NOLINT(*-non-private-member-variables-in-classes)
667
};
668

669
class Client_Context : public TLS_Context {
670
   public:
671
      Client_Context(std::shared_ptr<Botan::RandomNumberGenerator> rng_in,
6✔
672
                     std::shared_ptr<const RFC8448_Text_Policy> policy,
673
                     uint64_t timestamp,
674
                     Modify_Exts_Fn modify_exts_cb,
675
                     std::optional<std::pair<Session, Session_Ticket>> session_and_ticket = std::nullopt,
676
                     std::optional<ExternalPSK> external_psk = std::nullopt,
677
                     std::vector<MockSignature> mock_signatures = {}) :
6✔
678
            TLS_Context(std::move(rng_in),
6✔
679
                        std::move(policy),
6✔
680
                        std::move(modify_exts_cb),
6✔
681
                        std::move(mock_signatures),
6✔
682
                        timestamp,
683
                        std::move(session_and_ticket),
6✔
684
                        std::move(external_psk),
6✔
685
                        false),
686
            client(m_callbacks,
24✔
687
                   m_session_mgr,
6✔
688
                   m_creds,
6✔
689
                   m_policy,
6✔
690
                   m_rng,
6✔
691
                   Botan::TLS::Server_Information("server"),
12✔
692
                   Botan::TLS::Protocol_Version::TLS_V13) {}
27✔
693

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

696
      Botan::TLS::Client client;  // NOLINT(*-non-private-member-variables-in-classes)
697
};
698

699
class Server_Context : public TLS_Context {
700
   public:
701
      Server_Context(std::shared_ptr<Botan::RandomNumberGenerator> rng,
6✔
702
                     std::shared_ptr<const RFC8448_Text_Policy> policy,
703
                     uint64_t timestamp,
704
                     Modify_Exts_Fn modify_exts_cb,
705
                     std::vector<MockSignature> mock_signatures,
706
                     bool use_alternative_server_certificate = false,
707
                     std::optional<std::pair<Session, Session_Ticket>> session_and_ticket = std::nullopt,
708
                     std::optional<ExternalPSK> external_psk = std::nullopt) :
6✔
709
            TLS_Context(std::move(rng),
6✔
710
                        std::move(policy),
6✔
711
                        std::move(modify_exts_cb),
6✔
712
                        std::move(mock_signatures),
6✔
713
                        timestamp,
714
                        std::move(session_and_ticket),
6✔
715
                        std::move(external_psk),
6✔
716
                        use_alternative_server_certificate),
717
            server(m_callbacks, m_session_mgr, m_creds, m_policy, m_rng, false /* DTLS NYI */) {}
46✔
718

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

721
      Botan::TLS::Server server;  // NOLINT(*-non-private-member-variables-in-classes)
722
};
723

724
void sort_extensions(Botan::TLS::Extensions& exts, const std::vector<Botan::TLS::Extension_Code>& expected_order) {
25✔
725
   for(const auto ext_type : expected_order) {
245✔
726
      auto ext = exts.take(ext_type);
220✔
727
      if(ext != nullptr) {
220✔
728
         exts.add(std::move(ext));
196✔
729
      }
730
   }
220✔
731
}
25✔
732

733
/**
734
 * Because of the nature of the RFC 8448 test data we need to produce bit-compatible
735
 * TLS messages. Hence we sort the generated TLS extensions exactly as expected.
736
 */
737
void sort_rfc8448_extensions(Botan::TLS::Extensions& exts,
22✔
738
                             Botan::TLS::Connection_Side side,
739
                             Botan::TLS::Handshake_Type = Botan::TLS::Handshake_Type::ClientHello) {
740
   if(side == Botan::TLS::Connection_Side::Client) {
22✔
741
      sort_extensions(exts,
12✔
742
                      {
743
                         Botan::TLS::Extension_Code::ServerNameIndication,
744
                         Botan::TLS::Extension_Code::SafeRenegotiation,
745
                         Botan::TLS::Extension_Code::SupportedGroups,
746
                         Botan::TLS::Extension_Code::SessionTicket,
747
                         Botan::TLS::Extension_Code::KeyShare,
748
                         Botan::TLS::Extension_Code::EarlyData,
749
                         Botan::TLS::Extension_Code::SupportedVersions,
750
                         Botan::TLS::Extension_Code::SignatureAlgorithms,
751
                         Botan::TLS::Extension_Code::Cookie,
752
                         Botan::TLS::Extension_Code::PskKeyExchangeModes,
753
                         Botan::TLS::Extension_Code::RecordSizeLimit,
754
                         Padding::static_type(),
755
                         Botan::TLS::Extension_Code::PresharedKey,
756
                      });
757
   } else {
758
      sort_extensions(exts,
32✔
759
                      {
760
                         Botan::TLS::Extension_Code::SupportedGroups,
761
                         Botan::TLS::Extension_Code::KeyShare,
762
                         Botan::TLS::Extension_Code::Cookie,
763
                         Botan::TLS::Extension_Code::SupportedVersions,
764
                         Botan::TLS::Extension_Code::SignatureAlgorithms,
765
                         Botan::TLS::Extension_Code::RecordSizeLimit,
766
                         Botan::TLS::Extension_Code::ServerNameIndication,
767
                         Botan::TLS::Extension_Code::EarlyData,
768
                      });
769
   }
770
}
22✔
771

772
void add_renegotiation_extension(Botan::TLS::Extensions& exts) {
5✔
773
   // Renegotiation is not possible in TLS 1.3. Nevertheless, RFC 8448 requires
774
   // to add this to the Client Hello for reasons.
775
   exts.add(new Renegotiation_Extension());
5✔
776
}
5✔
777

778
void add_early_data_indication(Botan::TLS::Extensions& exts) {
1✔
779
   exts.add(new Botan::TLS::EarlyDataIndication());
1✔
780
}
1✔
781

782
std::vector<uint8_t> strip_message_header(const std::vector<uint8_t>& msg) {
25✔
783
   BOTAN_ASSERT_NOMSG(msg.size() >= 4);
25✔
784
   return {msg.begin() + 4, msg.end()};
25✔
785
}
786

787
std::vector<MockSignature> make_mock_signatures(const VarMap& vars) {
7✔
788
   std::vector<MockSignature> result;
7✔
789

790
   auto mock = [&](const std::string& msg, const std::string& sig) {
21✔
791
      if(vars.has_key(msg) && vars.has_key(sig)) {
35✔
792
         result.push_back({vars.get_opt_bin(msg), vars.get_opt_bin(sig)});
7✔
793
      }
794
   };
14✔
795

796
   mock("Server_MessageToSign", "Server_MessageSignature");
14✔
797
   mock("Client_MessageToSign", "Client_MessageSignature");
14✔
798

799
   return result;
7✔
800
}
×
801

802
}  // namespace
803

804
/**
805
 * Traffic transcripts and supporting data for the TLS RFC 8448 and TLS policy
806
 * configuration is kept in data files (accessible via `Test:::data_file()`).
807
 *
808
 * tls_13_rfc8448/transcripts.vec
809
 *   The record transcripts and RNG outputs as defined/required in RFC 8448 in
810
 *   Botan's Text_Based_Test vector format. Data from each RFC 8448 section is
811
 *   placed in a sub-section of the *.vec file. Each of those sections needs a
812
 *   specific test case implementation that is dispatched in `run_one_test()`.
813
 *
814
 * tls_13_rfc8448/client_certificate.pem
815
 *   The client certificate provided in RFC 8448 used to perform client auth.
816
 *   Note that RFC 8448 _does not_ provide the associated private key but only
817
 *   the resulting signature in the client's CertificateVerify message.
818
 *
819
 * tls_13_rfc8448/server_certificate.pem
820
 * tls_13_rfc8448/server_key.pem
821
 *   The server certificate and its associated private key.
822
 *
823
 * tls_13_rfc8448/server_certificate_client_auth.pem
824
 *   The server certificate used in the Client Authentication test case.
825
 *
826
 * tls-policy/rfc8448_*.txt
827
 *   Each RFC 8448 section test required a slightly adapted Botan TLS policy
828
 *   to enable/disable certain features under test.
829
 *
830
 * While the test cases are split into Client-side and Server-side tests, the
831
 * transcript data is reused. See the concrete implementations of the abstract
832
 * Test_TLS_RFC8448 test class.
833
 */
834
class Test_TLS_RFC8448 : public Text_Based_Test {
835
   protected:
836
      // Those tests are based on the test vectors in RFC8448.
837
      virtual std::vector<Test::Result> simple_1_rtt(const VarMap& vars) = 0;
838
      virtual std::vector<Test::Result> resumed_handshake_with_0_rtt(const VarMap& vars) = 0;
839
      virtual std::vector<Test::Result> hello_retry_request(const VarMap& vars) = 0;
840
      virtual std::vector<Test::Result> client_authentication(const VarMap& vars) = 0;
841
      virtual std::vector<Test::Result> middlebox_compatibility(const VarMap& vars) = 0;
842

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

847
      virtual std::string side() const = 0;
848

849
   public:
850
      Test_TLS_RFC8448() :
2✔
851
            Text_Based_Test("tls_13_rfc8448/transcripts.vec",
852
                            // mandatory data fields
853
                            "Client_RNG_Pool,"
854
                            "Server_RNG_Pool,"
855
                            "CurrentTimestamp,"
856
                            "Record_ClientHello_1,"
857
                            "Record_ServerHello,"
858
                            "Record_ServerHandshakeMessages,"
859
                            "Record_ClientFinished,"
860
                            "Record_Client_CloseNotify,"
861
                            "Record_Server_CloseNotify",
862
                            // optional data fields
863
                            "Message_ServerHello,"
864
                            "Message_EncryptedExtensions,"
865
                            "Message_CertificateRequest,"
866
                            "Message_Server_Certificate,"
867
                            "Message_Server_CertificateVerify,"
868
                            "Message_Server_Finished,"
869
                            "Record_HelloRetryRequest,"
870
                            "Record_ClientHello_2,"
871
                            "Record_NewSessionTicket,"
872
                            "Client_AppData,"
873
                            "Record_Client_AppData,"
874
                            "Server_AppData,"
875
                            "Record_Server_AppData,"
876
                            "Client_EarlyAppData,"
877
                            "Record_Client_EarlyAppData,"
878
                            "SessionTicket,"
879
                            "Client_SessionData,"
880
                            "Server_MessageToSign,"
881
                            "Server_MessageSignature,"
882
                            "Client_MessageToSign,"
883
                            "Client_MessageSignature,"
884
                            "HelloRetryRequest_Cookie,"
885
                            "PskIdentity,"
886
                            "PskPRF,"
887
                            "PskSecret") {}
8✔
888

889
      Test::Result run_one_test(const std::string& header, const VarMap& vars) override {
12✔
890
         if(header == "Simple_1RTT_Handshake") {
12✔
891
            return Test::Result("Simple 1-RTT (" + side() + " side)", simple_1_rtt(vars));
4✔
892
         } else if(header == "Resumed_0RTT_Handshake") {
10✔
893
            return Test::Result("Resumption with 0-RTT data (" + side() + " side)", resumed_handshake_with_0_rtt(vars));
4✔
894
         } else if(header == "HelloRetryRequest_Handshake") {
8✔
895
            return Test::Result("Handshake involving Hello Retry Request (" + side() + " side)",
4✔
896
                                hello_retry_request(vars));
6✔
897
         } else if(header == "Client_Authentication_Handshake") {
6✔
898
            return Test::Result("Client Authentication (" + side() + " side)", client_authentication(vars));
4✔
899
         } else if(header == "Middlebox_Compatibility_Mode") {
4✔
900
            return Test::Result("Middlebox Compatibility Mode (" + side() + " side)", middlebox_compatibility(vars));
4✔
901
         } else if(header == "Externally_Provided_PSK_with_Ephemeral_Key") {
2✔
902
            return Test::Result("Externally Provided PSK with ephemeral key (" + side() + " side)",
4✔
903
                                externally_provided_psk_with_ephemeral_key(vars));
6✔
904
         } else {
905
            return Test::Result::Failure("test dispatcher", "unknown sub-test: " + header);
×
906
         }
907
      }
908
};
909

910
class Test_TLS_RFC8448_Client : public Test_TLS_RFC8448 {
1✔
911
   private:
912
      std::string side() const override { return "Client"; }
6✔
913

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

917
         // 32 - for client hello random
918
         // 32 - for KeyShare (eph. x25519 key pair)
919
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
920

921
         auto add_extensions_and_sort = [](Botan::TLS::Extensions& exts,
2✔
922
                                           Botan::TLS::Connection_Side side,
923
                                           Botan::TLS::Handshake_Type which_message) {
924
            if(which_message == Handshake_Type::ClientHello) {
1✔
925
               // For some reason, presumably checking compatibility, the RFC 8448 Client
926
               // Hello includes a (TLS 1.2) Session_Ticket extension. We don't normally add
927
               // this obsoleted extension in a TLS 1.3 client.
928
               exts.add(new Botan::TLS::Session_Ticket_Extension());
1✔
929

930
               add_renegotiation_extension(exts);
1✔
931
               sort_rfc8448_extensions(exts, side);
1✔
932
            }
933
         };
1✔
934

935
         std::unique_ptr<Client_Context> ctx;
1✔
936

937
         return {
1✔
938
            Botan_Tests::CHECK(
939
               "Client Hello",
940
               [&](Test::Result& result) {
1✔
941
                  ctx = std::make_unique<Client_Context>(rng,
3✔
942
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
943
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
944
                                                         add_extensions_and_sort);
2✔
945

946
                  result.confirm("client not closed", !ctx->client.is_closed());
2✔
947
                  ctx->check_callback_invocations(result,
7✔
948
                                                  "client hello prepared",
949
                                                  {
950
                                                     "tls_emit_data",
951
                                                     "tls_inspect_handshake_msg_client_hello",
952
                                                     "tls_modify_extensions_client_hello",
953
                                                     "tls_generate_ephemeral_key",
954
                                                     "tls_current_timestamp",
955
                                                  });
956

957
                  result.test_eq("TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
958
               }),
1✔
959

960
            Botan_Tests::CHECK(
961
               "Server Hello",
962
               [&](Test::Result& result) {
1✔
963
                  result.require("ctx is available", ctx != nullptr);
1✔
964
                  const auto server_hello = vars.get_req_bin("Record_ServerHello");
1✔
965
                  // splitting the input data to test partial reads
966
                  const std::vector<uint8_t> server_hello_a(server_hello.begin(), server_hello.begin() + 20);
1✔
967
                  const std::vector<uint8_t> server_hello_b(server_hello.begin() + 20, server_hello.end());
1✔
968

969
                  ctx->client.received_data(server_hello_a);
1✔
970
                  ctx->check_callback_invocations(result, "server hello partially received", {});
2✔
971

972
                  ctx->client.received_data(server_hello_b);
1✔
973
                  ctx->check_callback_invocations(result,
5✔
974
                                                  "server hello received",
975
                                                  {"tls_inspect_handshake_msg_server_hello",
976
                                                   "tls_examine_extensions_server_hello",
977
                                                   "tls_ephemeral_key_agreement"});
978

979
                  result.confirm("client is not yet active", !ctx->client.is_active());
3✔
980
               }),
3✔
981

982
            Botan_Tests::CHECK(
983
               "Server HS messages .. Client Finished",
984
               [&](Test::Result& result) {
1✔
985
                  result.require("ctx is available", ctx != nullptr);
3✔
986
                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
987

988
                  ctx->check_callback_invocations(result,
14✔
989
                                                  "encrypted handshake messages received",
990
                                                  {"tls_inspect_handshake_msg_encrypted_extensions",
991
                                                   "tls_inspect_handshake_msg_certificate",
992
                                                   "tls_inspect_handshake_msg_certificate_verify",
993
                                                   "tls_inspect_handshake_msg_finished",
994
                                                   "tls_examine_extensions_encrypted_extensions",
995
                                                   "tls_examine_extensions_certificate",
996
                                                   "tls_emit_data",
997
                                                   "tls_current_timestamp",
998
                                                   "tls_session_established",
999
                                                   "tls_session_activated",
1000
                                                   "tls_verify_cert_chain",
1001
                                                   "tls_verify_message"});
1002
                  result.require("certificate exists", !ctx->certs_verified().empty());
1✔
1003
                  result.require("correct certificate", ctx->certs_verified().front() == server_certificate());
2✔
1004
                  result.require("client is active", ctx->client.is_active());
1✔
1005

1006
                  result.test_eq(
3✔
1007
                     "correct handshake finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
3✔
1008
               }),
1✔
1009

1010
            Botan_Tests::CHECK("Post-Handshake: NewSessionTicket",
1011
                               [&](Test::Result& result) {
1✔
1012
                                  result.require("ctx is available", ctx != nullptr);
1✔
1013
                                  result.require("no sessions so far", ctx->stored_sessions().empty());
1✔
1014
                                  ctx->client.received_data(vars.get_req_bin("Record_NewSessionTicket"));
2✔
1015

1016
                                  ctx->check_callback_invocations(result,
5✔
1017
                                                                  "new session ticket received",
1018
                                                                  {"tls_examine_extensions_new_session_ticket",
1019
                                                                   "tls_should_persist_resumption_information",
1020
                                                                   "tls_current_timestamp"});
1021
                                  if(result.test_eq("session was stored", ctx->stored_sessions().size(), 1)) {
2✔
1022
                                     const auto& [stored_session, stored_handle] = ctx->stored_sessions().front();
1✔
1023
                                     result.require("session handle contains a ticket",
2✔
1024
                                                    stored_handle.ticket().has_value());
1✔
1025
                                     result.test_is_eq("session was serialized as expected",
3✔
1026
                                                       Botan::unlock(stored_session.DER_encode()),
4✔
1027
                                                       vars.get_req_bin("Client_SessionData"));
3✔
1028
                                  }
1029
                               }),
1✔
1030

1031
            Botan_Tests::CHECK("Send Application Data",
1032
                               [&](Test::Result& result) {
1✔
1033
                                  result.require("ctx is available", ctx != nullptr);
2✔
1034
                                  ctx->send(vars.get_req_bin("Client_AppData"));
3✔
1035

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

1038
                                  result.test_eq("correct client application data",
3✔
1039
                                                 ctx->pull_send_buffer(),
2✔
1040
                                                 vars.get_req_bin("Record_Client_AppData"));
2✔
1041
                               }),
1✔
1042

1043
            Botan_Tests::CHECK(
1044
               "Receive Application Data",
1045
               [&](Test::Result& result) {
1✔
1046
                  result.require("ctx is available", ctx != nullptr);
1✔
1047
                  ctx->client.received_data(vars.get_req_bin("Record_Server_AppData"));
2✔
1048

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

1051
                  const auto rcvd = ctx->pull_receive_buffer();
1✔
1052
                  result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Server_AppData"));
3✔
1053
                  result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(1));
2✔
1054
               }),
1✔
1055

1056
            Botan_Tests::CHECK("Close Connection",
1057
                               [&](Test::Result& result) {
1✔
1058
                                  result.require("ctx is available", ctx != nullptr);
2✔
1059
                                  ctx->client.close();
1✔
1060

1061
                                  result.test_eq("close payload",
2✔
1062
                                                 ctx->pull_send_buffer(),
2✔
1063
                                                 vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1064
                                  ctx->check_callback_invocations(result, "CLOSE_NOTIFY sent", {"tls_emit_data"});
3✔
1065

1066
                                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1067
                                  ctx->check_callback_invocations(
4✔
1068
                                     result, "CLOSE_NOTIFY received", {"tls_alert", "tls_peer_closed_connection"});
1069

1070
                                  result.confirm("connection is closed", ctx->client.is_closed());
2✔
1071
                               }),
1✔
1072
         };
8✔
1073
      }
2✔
1074

1075
      std::vector<Test::Result> resumed_handshake_with_0_rtt(const VarMap& vars) override {
1✔
1076
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>("");
1✔
1077

1078
         // 32 - for client hello random
1079
         // 32 - for KeyShare (eph. x25519 key pair)
1080
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1081

1082
         auto add_extensions_and_sort = [](Botan::TLS::Extensions& exts,
2✔
1083
                                           Botan::TLS::Connection_Side side,
1084
                                           Botan::TLS::Handshake_Type which_message) {
1085
            if(which_message == Handshake_Type::ClientHello) {
1✔
1086
               exts.add(new Padding(87));
1✔
1087

1088
               add_renegotiation_extension(exts);
1✔
1089

1090
               // TODO: Implement early data support and remove this 'hack'.
1091
               //
1092
               // Currently, the production implementation will never add this
1093
               // extension even if the resumed session would allow early data.
1094
               add_early_data_indication(exts);
1✔
1095
               sort_rfc8448_extensions(exts, side);
1✔
1096
            }
1097
         };
1✔
1098

1099
         std::unique_ptr<Client_Context> ctx;
1✔
1100

1101
         return {
1✔
1102
            Botan_Tests::CHECK(
1103
               "Client Hello",
1104
               [&](Test::Result& result) {
1✔
1105
                  ctx = std::make_unique<Client_Context>(
3✔
1106
                     std::move(rng),
1✔
1107
                     std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
1108
                     vars.get_req_u64("CurrentTimestamp"),
4✔
1109
                     add_extensions_and_sort,
1✔
1110
                     std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
1111
                               Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1112

1113
                  result.confirm("client not closed", !ctx->client.is_closed());
2✔
1114
                  ctx->check_callback_invocations(result,
7✔
1115
                                                  "client hello prepared",
1116
                                                  {
1117
                                                     "tls_emit_data",
1118
                                                     "tls_inspect_handshake_msg_client_hello",
1119
                                                     "tls_modify_extensions_client_hello",
1120
                                                     "tls_current_timestamp",
1121
                                                     "tls_generate_ephemeral_key",
1122
                                                  });
1123

1124
                  result.test_eq("TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1125
               })
1✔
1126

1127
            // TODO: The rest of this test vector requires 0-RTT which is not
1128
            //       yet implemented. For now we can only test the client's
1129
            //       ability to offer a session resumption via PSK.
1130
         };
2✔
1131
      }
1✔
1132

1133
      std::vector<Test::Result> hello_retry_request(const VarMap& vars) override {
1✔
1134
         auto add_extensions_and_sort = [flights = 0](Botan::TLS::Extensions& exts,
3✔
1135
                                                      Botan::TLS::Connection_Side side,
1136
                                                      Botan::TLS::Handshake_Type which_message) mutable {
4✔
1137
            if(which_message == Handshake_Type::ClientHello) {
2✔
1138
               ++flights;
2✔
1139

1140
               if(flights == 1) {
2✔
1141
                  add_renegotiation_extension(exts);
1✔
1142
               }
1143

1144
               // For some reason RFC8448 decided to require this (fairly obscure) extension
1145
               // in the second flight of the Client_Hello.
1146
               if(flights == 2) {
2✔
1147
                  exts.add(new Padding(175));
1✔
1148
               }
1149

1150
               sort_rfc8448_extensions(exts, side);
2✔
1151
            }
1152
         };
2✔
1153

1154
         // Fallback RNG is required to for blinding in ECDH with P-256
1155
         auto& fallback_rng = Test::rng();
1✔
1156
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>(fallback_rng);
1✔
1157

1158
         // 32 - client hello random
1159
         // 32 - eph. x25519 key pair
1160
         // 32 - eph. P-256 key pair
1161
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1162

1163
         std::unique_ptr<Client_Context> ctx;
1✔
1164

1165
         return {
1✔
1166
            Botan_Tests::CHECK(
1167
               "Client Hello",
1168
               [&](Test::Result& result) {
1✔
1169
                  ctx = std::make_unique<Client_Context>(std::move(rng),
3✔
1170
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_hrr_client"),
1✔
1171
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
1172
                                                         add_extensions_and_sort);
2✔
1173
                  result.confirm("client not closed", !ctx->client.is_closed());
2✔
1174

1175
                  ctx->check_callback_invocations(result,
7✔
1176
                                                  "client hello prepared",
1177
                                                  {
1178
                                                     "tls_emit_data",
1179
                                                     "tls_inspect_handshake_msg_client_hello",
1180
                                                     "tls_modify_extensions_client_hello",
1181
                                                     "tls_generate_ephemeral_key",
1182
                                                     "tls_current_timestamp",
1183
                                                  });
1184

1185
                  result.test_eq(
3✔
1186
                     "TLS client hello (1)", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
3✔
1187
               }),
1✔
1188

1189
            Botan_Tests::CHECK("Hello Retry Request .. second Client Hello",
1190
                               [&](Test::Result& result) {
1✔
1191
                                  result.require("ctx is available", ctx != nullptr);
2✔
1192
                                  ctx->client.received_data(vars.get_req_bin("Record_HelloRetryRequest"));
2✔
1193

1194
                                  ctx->check_callback_invocations(result,
8✔
1195
                                                                  "hello retry request received",
1196
                                                                  {
1197
                                                                     "tls_emit_data",
1198
                                                                     "tls_inspect_handshake_msg_hello_retry_request",
1199
                                                                     "tls_examine_extensions_hello_retry_request",
1200
                                                                     "tls_inspect_handshake_msg_client_hello",
1201
                                                                     "tls_modify_extensions_client_hello",
1202
                                                                     "tls_generate_ephemeral_key",
1203
                                                                  });
1204

1205
                                  result.test_eq("TLS client hello (2)",
3✔
1206
                                                 ctx->pull_send_buffer(),
2✔
1207
                                                 vars.get_req_bin("Record_ClientHello_2"));
2✔
1208
                               }),
1✔
1209

1210
            Botan_Tests::CHECK("Server Hello",
1211
                               [&](Test::Result& result) {
1✔
1212
                                  result.require("ctx is available", ctx != nullptr);
1✔
1213
                                  ctx->client.received_data(vars.get_req_bin("Record_ServerHello"));
2✔
1214

1215
                                  ctx->check_callback_invocations(result,
5✔
1216
                                                                  "server hello received",
1217
                                                                  {
1218
                                                                     "tls_inspect_handshake_msg_server_hello",
1219
                                                                     "tls_examine_extensions_server_hello",
1220
                                                                     "tls_ephemeral_key_agreement",
1221
                                                                  });
1222
                               }),
1✔
1223

1224
            Botan_Tests::CHECK(
1225
               "Server HS Messages .. Client Finished",
1226
               [&](Test::Result& result) {
1✔
1227
                  result.require("ctx is available", ctx != nullptr);
2✔
1228
                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
1229

1230
                  ctx->check_callback_invocations(result,
14✔
1231
                                                  "encrypted handshake messages received",
1232
                                                  {"tls_inspect_handshake_msg_encrypted_extensions",
1233
                                                   "tls_inspect_handshake_msg_certificate",
1234
                                                   "tls_inspect_handshake_msg_certificate_verify",
1235
                                                   "tls_inspect_handshake_msg_finished",
1236
                                                   "tls_examine_extensions_encrypted_extensions",
1237
                                                   "tls_examine_extensions_certificate",
1238
                                                   "tls_emit_data",
1239
                                                   "tls_current_timestamp",
1240
                                                   "tls_session_established",
1241
                                                   "tls_session_activated",
1242
                                                   "tls_verify_cert_chain",
1243
                                                   "tls_verify_message"});
1244

1245
                  result.test_eq("client finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
4✔
1246
               }),
1✔
1247

1248
            Botan_Tests::CHECK(
1249
               "Close Connection",
1250
               [&](Test::Result& result) {
1✔
1251
                  result.require("ctx is available", ctx != nullptr);
2✔
1252
                  ctx->client.close();
1✔
1253
                  ctx->check_callback_invocations(result, "encrypted handshake messages received", {"tls_emit_data"});
3✔
1254
                  result.test_eq(
2✔
1255
                     "client close notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1256

1257
                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1258
                  ctx->check_callback_invocations(
4✔
1259
                     result, "encrypted handshake messages received", {"tls_alert", "tls_peer_closed_connection"});
1260

1261
                  result.confirm("connection is closed", ctx->client.is_closed());
2✔
1262
               }),
1✔
1263
         };
6✔
1264
      }
1✔
1265

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

1269
         // 32 - for client hello random
1270
         // 32 - for eph. x25519 key pair
1271
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1272

1273
         auto add_extensions_and_sort = [&](Botan::TLS::Extensions& exts,
3✔
1274
                                            Botan::TLS::Connection_Side side,
1275
                                            Botan::TLS::Handshake_Type which_message) {
1276
            if(which_message == Handshake_Type::ClientHello) {
2✔
1277
               add_renegotiation_extension(exts);
1✔
1278
               sort_rfc8448_extensions(exts, side);
1✔
1279
            }
1280
         };
1281

1282
         std::unique_ptr<Client_Context> ctx;
1✔
1283

1284
         return {
1✔
1285
            Botan_Tests::CHECK(
1286
               "Client Hello",
1287
               [&](Test::Result& result) {
1✔
1288
                  ctx = std::make_unique<Client_Context>(std::move(rng),
3✔
1289
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
1290
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
1291
                                                         add_extensions_and_sort,
1✔
1292
                                                         std::nullopt,
1293
                                                         std::nullopt,
1294
                                                         make_mock_signatures(vars));
3✔
1295

1296
                  ctx->check_callback_invocations(result,
7✔
1297
                                                  "initial callbacks",
1298
                                                  {
1299
                                                     "tls_emit_data",
1300
                                                     "tls_inspect_handshake_msg_client_hello",
1301
                                                     "tls_modify_extensions_client_hello",
1302
                                                     "tls_generate_ephemeral_key",
1303
                                                     "tls_current_timestamp",
1304
                                                  });
1305

1306
                  result.test_eq("Client Hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1307
               }),
1✔
1308

1309
            Botan_Tests::CHECK("Server Hello",
1310
                               [&](auto& result) {
1✔
1311
                                  result.require("ctx is available", ctx != nullptr);
2✔
1312
                                  ctx->client.received_data(vars.get_req_bin("Record_ServerHello"));
3✔
1313

1314
                                  ctx->check_callback_invocations(result,
5✔
1315
                                                                  "callbacks after server hello",
1316
                                                                  {
1317
                                                                     "tls_examine_extensions_server_hello",
1318
                                                                     "tls_inspect_handshake_msg_server_hello",
1319
                                                                     "tls_ephemeral_key_agreement",
1320
                                                                  });
1321
                               }),
1✔
1322

1323
            Botan_Tests::CHECK("other handshake messages and client auth",
1324
                               [&](Test::Result& result) {
1✔
1325
                                  result.require("ctx is available", ctx != nullptr);
2✔
1326
                                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
1327

1328
                                  ctx->check_callback_invocations(result,
18✔
1329
                                                                  "signing callbacks invoked",
1330
                                                                  {
1331
                                                                     "tls_sign_message",
1332
                                                                     "tls_emit_data",
1333
                                                                     "tls_examine_extensions_encrypted_extensions",
1334
                                                                     "tls_examine_extensions_certificate",
1335
                                                                     "tls_examine_extensions_certificate_request",
1336
                                                                     "tls_modify_extensions_certificate",
1337
                                                                     "tls_inspect_handshake_msg_certificate",
1338
                                                                     "tls_inspect_handshake_msg_certificate_request",
1339
                                                                     "tls_inspect_handshake_msg_certificate_verify",
1340
                                                                     "tls_inspect_handshake_msg_encrypted_extensions",
1341
                                                                     "tls_inspect_handshake_msg_finished",
1342
                                                                     "tls_current_timestamp",
1343
                                                                     "tls_session_established",
1344
                                                                     "tls_session_activated",
1345
                                                                     "tls_verify_cert_chain",
1346
                                                                     "tls_verify_message",
1347
                                                                  });
1348

1349
                                  // ClientFinished contains the entire coalesced client authentication flight
1350
                                  // Messages: Certificate, CertificateVerify, Finished
1351
                                  result.test_eq("Client Auth and Finished",
3✔
1352
                                                 ctx->pull_send_buffer(),
2✔
1353
                                                 vars.get_req_bin("Record_ClientFinished"));
2✔
1354
                               }),
1✔
1355

1356
            Botan_Tests::CHECK(
1357
               "Close Connection",
1358
               [&](Test::Result& result) {
1✔
1359
                  result.require("ctx is available", ctx != nullptr);
2✔
1360
                  ctx->client.close();
1✔
1361
                  result.test_eq(
2✔
1362
                     "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
4✔
1363

1364
                  ctx->check_callback_invocations(result,
3✔
1365
                                                  "after sending close notify",
1366
                                                  {
1367
                                                     "tls_emit_data",
1368
                                                  });
1369

1370
                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1371
                  result.confirm("connection closed", ctx->client.is_closed());
2✔
1372

1373
                  ctx->check_callback_invocations(
4✔
1374
                     result, "after receiving close notify", {"tls_alert", "tls_peer_closed_connection"});
1375
               }),
1✔
1376
         };
5✔
1377
      }
1✔
1378

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

1382
         // 32 - client hello random
1383
         // 32 - legacy session ID
1384
         // 32 - eph. x25519 key pair
1385
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1386

1387
         auto add_extensions_and_sort = [&](Botan::TLS::Extensions& exts,
2✔
1388
                                            Botan::TLS::Connection_Side side,
1389
                                            Botan::TLS::Handshake_Type which_message) {
1390
            if(which_message == Handshake_Type::ClientHello) {
1✔
1391
               add_renegotiation_extension(exts);
1✔
1392
               sort_rfc8448_extensions(exts, side);
1✔
1393
            }
1394
         };
1395

1396
         std::unique_ptr<Client_Context> ctx;
1✔
1397

1398
         return {
1✔
1399
            Botan_Tests::CHECK(
1400
               "Client Hello",
1401
               [&](Test::Result& result) {
1✔
1402
                  ctx = std::make_unique<Client_Context>(std::move(rng),
3✔
1403
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_compat_client"),
1✔
1404
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
1405
                                                         add_extensions_and_sort);
2✔
1406

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

1409
                  ctx->check_callback_invocations(result,
7✔
1410
                                                  "client hello prepared",
1411
                                                  {
1412
                                                     "tls_emit_data",
1413
                                                     "tls_inspect_handshake_msg_client_hello",
1414
                                                     "tls_modify_extensions_client_hello",
1415
                                                     "tls_generate_ephemeral_key",
1416
                                                     "tls_current_timestamp",
1417
                                                  });
1418
               }),
1✔
1419

1420
            Botan_Tests::CHECK("Server Hello + other handshake messages",
1421
                               [&](Test::Result& result) {
1✔
1422
                                  result.require("ctx is available", ctx != nullptr);
2✔
1423
                                  ctx->client.received_data(Botan::concat(
3✔
1424
                                     vars.get_req_bin("Record_ServerHello"),
4✔
1425
                                     // ServerHandshakeMessages contains the expected ChangeCipherSpec record
1426
                                     vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1427

1428
                                  ctx->check_callback_invocations(result,
17✔
1429
                                                                  "callbacks after server's first flight",
1430
                                                                  {
1431
                                                                     "tls_inspect_handshake_msg_server_hello",
1432
                                                                     "tls_inspect_handshake_msg_encrypted_extensions",
1433
                                                                     "tls_inspect_handshake_msg_certificate",
1434
                                                                     "tls_inspect_handshake_msg_certificate_verify",
1435
                                                                     "tls_inspect_handshake_msg_finished",
1436
                                                                     "tls_examine_extensions_server_hello",
1437
                                                                     "tls_examine_extensions_encrypted_extensions",
1438
                                                                     "tls_examine_extensions_certificate",
1439
                                                                     "tls_emit_data",
1440
                                                                     "tls_current_timestamp",
1441
                                                                     "tls_session_established",
1442
                                                                     "tls_session_activated",
1443
                                                                     "tls_verify_cert_chain",
1444
                                                                     "tls_verify_message",
1445
                                                                     "tls_ephemeral_key_agreement",
1446
                                                                  });
1447

1448
                                  result.test_eq("CCS + Client Finished",
3✔
1449
                                                 ctx->pull_send_buffer(),
2✔
1450
                                                 // ClientFinished contains the expected ChangeCipherSpec record
1451
                                                 vars.get_req_bin("Record_ClientFinished"));
2✔
1452

1453
                                  result.confirm("client is ready to send application traffic",
2✔
1454
                                                 ctx->client.is_active());
1✔
1455
                               }),
1✔
1456

1457
            Botan_Tests::CHECK(
1458
               "Close connection",
1459
               [&](Test::Result& result) {
1✔
1460
                  result.require("ctx is available", ctx != nullptr);
2✔
1461
                  ctx->client.close();
1✔
1462

1463
                  result.test_eq(
2✔
1464
                     "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
4✔
1465

1466
                  result.require("client cannot send application traffic anymore", !ctx->client.is_active());
1✔
1467
                  result.require("client is not fully closed yet", !ctx->client.is_closed());
1✔
1468

1469
                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1470

1471
                  result.confirm("client connection was terminated", ctx->client.is_closed());
2✔
1472
               }),
1✔
1473
         };
4✔
1474
      }
1✔
1475

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

1479
         // 32 - for client hello random
1480
         // 32 - for KeyShare (eph. x25519 key pair)
1481
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1482

1483
         auto sort_our_extensions = [](Botan::TLS::Extensions& exts,
2✔
1484
                                       Botan::TLS::Connection_Side /* side */,
1485
                                       Botan::TLS::Handshake_Type /* which_message */) {
1486
            // This is the order of extensions when we first introduced the PSK
1487
            // implementation and generated the transcript. To stay compatible
1488
            // with the now hard-coded transcript, we pin the extension order.
1489
            sort_extensions(exts,
1✔
1490
                            {
1491
                               Botan::TLS::Extension_Code::ServerNameIndication,
1492
                               Botan::TLS::Extension_Code::SupportedGroups,
1493
                               Botan::TLS::Extension_Code::KeyShare,
1494
                               Botan::TLS::Extension_Code::SupportedVersions,
1495
                               Botan::TLS::Extension_Code::SignatureAlgorithms,
1496
                               Botan::TLS::Extension_Code::PskKeyExchangeModes,
1497
                               Botan::TLS::Extension_Code::RecordSizeLimit,
1498
                               Botan::TLS::Extension_Code::PresharedKey,
1499
                            });
1500
         };
1✔
1501

1502
         std::unique_ptr<Client_Context> ctx;
1✔
1503

1504
         return {
1✔
1505
            Botan_Tests::CHECK(
1506
               "Client Hello",
1507
               [&](Test::Result& result) {
1✔
1508
                  ctx = std::make_unique<Client_Context>(
3✔
1509
                     std::move(rng),
1✔
1510
                     std::make_shared<RFC8448_Text_Policy>("rfc8448_psk_dhe", false /* no rfc8448 */),
1✔
1511
                     vars.get_req_u64("CurrentTimestamp"),
3✔
1512
                     sort_our_extensions,
1✔
1513
                     std::nullopt,
1514
                     ExternalPSK(vars.get_req_str("PskIdentity"),
2✔
1515
                                 vars.get_req_str("PskPRF"),
2✔
1516
                                 lock(vars.get_req_bin("PskSecret"))));
5✔
1517

1518
                  result.confirm("client not closed", !ctx->client.is_closed());
2✔
1519
                  ctx->check_callback_invocations(result,
7✔
1520
                                                  "client hello prepared",
1521
                                                  {
1522
                                                     "tls_emit_data",
1523
                                                     "tls_inspect_handshake_msg_client_hello",
1524
                                                     "tls_modify_extensions_client_hello",
1525
                                                     "tls_current_timestamp",
1526
                                                     "tls_generate_ephemeral_key",
1527
                                                  });
1528

1529
                  result.test_eq("TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1530
               }),
1✔
1531

1532
            Botan_Tests::CHECK("Server Hello",
1533
                               [&](Test::Result& result) {
1✔
1534
                                  result.require("ctx is available", ctx != nullptr);
1✔
1535
                                  const auto server_hello = vars.get_req_bin("Record_ServerHello");
1✔
1536
                                  ctx->client.received_data(server_hello);
1✔
1537
                                  ctx->check_callback_invocations(result,
5✔
1538
                                                                  "server hello received",
1539
                                                                  {"tls_inspect_handshake_msg_server_hello",
1540
                                                                   "tls_examine_extensions_server_hello",
1541
                                                                   "tls_ephemeral_key_agreement"});
1542

1543
                                  result.confirm("client is not yet active", !ctx->client.is_active());
3✔
1544
                               }),
1✔
1545

1546
            Botan_Tests::CHECK(
1547
               "Server HS messages .. Client Finished",
1548
               [&](Test::Result& result) {
1✔
1549
                  result.require("ctx is available", ctx != nullptr);
3✔
1550
                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
1551

1552
                  ctx->check_callback_invocations(result,
9✔
1553
                                                  "encrypted handshake messages received",
1554
                                                  {"tls_inspect_handshake_msg_encrypted_extensions",
1555
                                                   "tls_inspect_handshake_msg_finished",
1556
                                                   "tls_examine_extensions_encrypted_extensions",
1557
                                                   "tls_emit_data",
1558
                                                   "tls_current_timestamp",
1559
                                                   "tls_session_established",
1560
                                                   "tls_session_activated"});
1561
                  result.require("PSK negotiated", ctx->psk_identity_negotiated() == vars.get_req_str("PskIdentity"));
2✔
1562
                  result.require("client is active", ctx->client.is_active());
1✔
1563

1564
                  result.test_eq(
3✔
1565
                     "correct handshake finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
3✔
1566
               }),
1✔
1567

1568
            Botan_Tests::CHECK("Send Application Data",
1569
                               [&](Test::Result& result) {
1✔
1570
                                  result.require("ctx is available", ctx != nullptr);
2✔
1571
                                  ctx->send(vars.get_req_bin("Client_AppData"));
3✔
1572

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

1575
                                  result.test_eq("correct client application data",
3✔
1576
                                                 ctx->pull_send_buffer(),
2✔
1577
                                                 vars.get_req_bin("Record_Client_AppData"));
2✔
1578
                               }),
1✔
1579

1580
            Botan_Tests::CHECK(
1581
               "Receive Application Data",
1582
               [&](Test::Result& result) {
1✔
1583
                  result.require("ctx is available", ctx != nullptr);
1✔
1584
                  ctx->client.received_data(vars.get_req_bin("Record_Server_AppData"));
2✔
1585

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

1588
                  const auto rcvd = ctx->pull_receive_buffer();
1✔
1589
                  result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Server_AppData"));
3✔
1590
                  result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
2✔
1591
               }),
1✔
1592

1593
            Botan_Tests::CHECK("Close Connection",
1594
                               [&](Test::Result& result) {
1✔
1595
                                  result.require("ctx is available", ctx != nullptr);
2✔
1596
                                  ctx->client.close();
1✔
1597

1598
                                  result.test_eq("close payload",
2✔
1599
                                                 ctx->pull_send_buffer(),
2✔
1600
                                                 vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1601
                                  ctx->check_callback_invocations(result, "CLOSE_NOTIFY sent", {"tls_emit_data"});
3✔
1602

1603
                                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1604
                                  ctx->check_callback_invocations(
4✔
1605
                                     result, "CLOSE_NOTIFY received", {"tls_alert", "tls_peer_closed_connection"});
1606

1607
                                  result.confirm("connection is closed", ctx->client.is_closed());
2✔
1608
                               }),
1✔
1609
         };
7✔
1610
      }
1✔
1611
};
1612

1613
class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 {
1✔
1614
   private:
1615
      std::string side() const override { return "Server"; }
6✔
1616

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

1620
         // 32 - for server hello random
1621
         // 32 - for KeyShare (eph. x25519 key pair)  --  I guess?
1622
         //  4 - for ticket_age_add (in New Session Ticket)
1623
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1624

1625
         std::unique_ptr<Server_Context> ctx;
1✔
1626

1627
         return {
1✔
1628
            Botan_Tests::CHECK("Send Client Hello",
1629
                               [&](Test::Result& result) {
1✔
1630
                                  auto add_early_data_and_sort = [&](Botan::TLS::Extensions& exts,
5✔
1631
                                                                     Botan::TLS::Connection_Side side,
1632
                                                                     Botan::TLS::Handshake_Type type) {
1633
                                     if(type == Handshake_Type::NewSessionTicket) {
4✔
1634
                                        exts.add(new EarlyDataIndication(1024));
1✔
1635
                                     }
1636
                                     sort_rfc8448_extensions(exts, side, type);
4✔
1637
                                  };
4✔
1638

1639
                                  ctx = std::make_unique<Server_Context>(
2✔
1640
                                     std::move(rng),
1✔
1641
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
1642
                                     vars.get_req_u64("CurrentTimestamp"),
5✔
1643
                                     add_early_data_and_sort,
1644
                                     make_mock_signatures(vars),
1✔
1645
                                     false,
2✔
1646
                                     std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
1647
                                               Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1648
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
1649

1650
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1651

1652
                                  ctx->check_callback_invocations(result,
16✔
1653
                                                                  "client hello received",
1654
                                                                  {"tls_emit_data",
1655
                                                                   "tls_examine_extensions_client_hello",
1656
                                                                   "tls_modify_extensions_server_hello",
1657
                                                                   "tls_modify_extensions_encrypted_extensions",
1658
                                                                   "tls_modify_extensions_certificate",
1659
                                                                   "tls_sign_message",
1660
                                                                   "tls_generate_ephemeral_key",
1661
                                                                   "tls_ephemeral_key_agreement",
1662
                                                                   "tls_inspect_handshake_msg_client_hello",
1663
                                                                   "tls_inspect_handshake_msg_server_hello",
1664
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
1665
                                                                   "tls_inspect_handshake_msg_certificate",
1666
                                                                   "tls_inspect_handshake_msg_certificate_verify",
1667
                                                                   "tls_inspect_handshake_msg_finished"});
1668
                               }),
1✔
1669

1670
            Botan_Tests::CHECK("Verify generated messages in server's first flight",
1671
                               [&](Test::Result& result) {
1✔
1672
                                  result.require("ctx is available", ctx != nullptr);
2✔
1673
                                  const auto& msgs = ctx->observed_handshake_messages();
1✔
1674

1675
                                  result.test_eq("Server Hello",
2✔
1676
                                                 msgs.at("server_hello")[0],
2✔
1677
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
1678
                                  result.test_eq("Encrypted Extensions",
3✔
1679
                                                 msgs.at("encrypted_extensions")[0],
2✔
1680
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
1681
                                  result.test_eq("Certificate",
3✔
1682
                                                 msgs.at("certificate")[0],
2✔
1683
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
1684
                                  result.test_eq(
3✔
1685
                                     "CertificateVerify",
1686
                                     msgs.at("certificate_verify")[0],
2✔
1687
                                     strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
1688

1689
                                  result.test_eq("Server's entire first flight",
3✔
1690
                                                 ctx->pull_send_buffer(),
2✔
1691
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
1692
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1693

1694
                                  result.confirm("Server can now send application data", ctx->server.is_active());
3✔
1695
                               }),
1✔
1696

1697
            Botan_Tests::CHECK("Send Client Finished",
1698
                               [&](Test::Result& result) {
1✔
1699
                                  result.require("ctx is available", ctx != nullptr);
1✔
1700
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
1701

1702
                                  ctx->check_callback_invocations(result,
6✔
1703
                                                                  "client finished received",
1704
                                                                  {"tls_inspect_handshake_msg_finished",
1705
                                                                   "tls_current_timestamp",
1706
                                                                   "tls_session_established",
1707
                                                                   "tls_session_activated"});
1708
                               }),
1✔
1709

1710
            Botan_Tests::CHECK("Send Session Ticket",
1711
                               [&](Test::Result& result) {
1✔
1712
                                  result.require("ctx is available", ctx != nullptr);
1✔
1713
                                  const auto new_tickets = ctx->server.send_new_session_tickets(1);
1✔
1714

1715
                                  result.test_eq("session ticket was sent", new_tickets, 1);
1✔
1716

1717
                                  ctx->check_callback_invocations(result,
7✔
1718
                                                                  "issued new session ticket",
1719
                                                                  {"tls_inspect_handshake_msg_new_session_ticket",
1720
                                                                   "tls_current_timestamp",
1721
                                                                   "tls_emit_data",
1722
                                                                   "tls_modify_extensions_new_session_ticket",
1723
                                                                   "tls_should_persist_resumption_information"});
1724
                               }),
1✔
1725

1726
            Botan_Tests::CHECK("Verify generated new session ticket message",
1727
                               [&](Test::Result& result) {
1✔
1728
                                  result.require("ctx is available", ctx != nullptr);
2✔
1729
                                  result.test_eq("New Session Ticket",
2✔
1730
                                                 ctx->pull_send_buffer(),
2✔
1731
                                                 vars.get_req_bin("Record_NewSessionTicket"));
2✔
1732
                               }),
1✔
1733

1734
            Botan_Tests::CHECK(
1735
               "Receive Application Data",
1736
               [&](Test::Result& result) {
1✔
1737
                  result.require("ctx is available", ctx != nullptr);
1✔
1738
                  ctx->server.received_data(vars.get_req_bin("Record_Client_AppData"));
2✔
1739
                  ctx->check_callback_invocations(result, "application data received", {"tls_record_received"});
3✔
1740

1741
                  const auto rcvd = ctx->pull_receive_buffer();
1✔
1742
                  result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Client_AppData"));
3✔
1743
                  result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
2✔
1744
               }),
1✔
1745

1746
            Botan_Tests::CHECK("Send Application Data",
1747
                               [&](Test::Result& result) {
1✔
1748
                                  result.require("ctx is available", ctx != nullptr);
2✔
1749
                                  ctx->send(vars.get_req_bin("Server_AppData"));
3✔
1750

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

1753
                                  result.test_eq("correct server application data",
3✔
1754
                                                 ctx->pull_send_buffer(),
2✔
1755
                                                 vars.get_req_bin("Record_Server_AppData"));
2✔
1756
                               }),
1✔
1757

1758
            Botan_Tests::CHECK("Receive Client's close_notify",
1759
                               [&](Test::Result& result) {
1✔
1760
                                  result.require("ctx is available", ctx != nullptr);
1✔
1761
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
1762

1763
                                  ctx->check_callback_invocations(
4✔
1764
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
1765

1766
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
1767
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
1768
                               }),
1✔
1769

1770
            Botan_Tests::CHECK("Expect Server close_notify",
1771
                               [&](Test::Result& result) {
1✔
1772
                                  result.require("ctx is available", ctx != nullptr);
2✔
1773
                                  ctx->server.close();
1✔
1774

1775
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
1776
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
1777
                                  result.test_eq("Server's close notify",
2✔
1778
                                                 ctx->pull_send_buffer(),
2✔
1779
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1780
                               }),
1✔
1781
         };
10✔
1782
      }
1✔
1783

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

1787
         // 32 - for server hello random
1788
         // 32 - for KeyShare (eph. x25519 key pair)
1789
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1790

1791
         std::unique_ptr<Server_Context> ctx;
1✔
1792

1793
         return {
1✔
1794
            Botan_Tests::CHECK("Receive Client Hello",
1795
                               [&](Test::Result& result) {
1✔
1796
                                  auto add_cookie_and_sort = [&](Botan::TLS::Extensions& exts,
3✔
1797
                                                                 Botan::TLS::Connection_Side side,
1798
                                                                 Botan::TLS::Handshake_Type type) {
1799
                                     if(type == Handshake_Type::EncryptedExtensions) {
2✔
1800
                                        exts.add(new EarlyDataIndication());
1✔
1801
                                     }
1802
                                     sort_rfc8448_extensions(exts, side, type);
2✔
1803
                                  };
2✔
1804

1805
                                  ctx = std::make_unique<Server_Context>(
2✔
1806
                                     std::move(rng),
1✔
1807
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
1808
                                     vars.get_req_u64("CurrentTimestamp"),
5✔
1809
                                     add_cookie_and_sort,
1810
                                     make_mock_signatures(vars),
1✔
1811
                                     false,
2✔
1812
                                     std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
1813
                                               Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1814
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
1815

1816
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1817

1818
                                  ctx->check_callback_invocations(result,
13✔
1819
                                                                  "client hello received",
1820
                                                                  {
1821
                                                                     "tls_emit_data",
1822
                                                                     "tls_current_timestamp",
1823
                                                                     "tls_generate_ephemeral_key",
1824
                                                                     "tls_ephemeral_key_agreement",
1825
                                                                     "tls_examine_extensions_client_hello",
1826
                                                                     "tls_modify_extensions_server_hello",
1827
                                                                     "tls_modify_extensions_encrypted_extensions",
1828
                                                                     "tls_inspect_handshake_msg_client_hello",
1829
                                                                     "tls_inspect_handshake_msg_server_hello",
1830
                                                                     "tls_inspect_handshake_msg_encrypted_extensions",
1831
                                                                     "tls_inspect_handshake_msg_finished",
1832
                                                                  });
1833
                               }),
1✔
1834

1835
            Botan_Tests::CHECK("Verify generated messages in server's first flight",
1836
                               [&](Test::Result& result) {
1✔
1837
                                  result.require("ctx is available", ctx != nullptr);
2✔
1838
                                  const auto& msgs = ctx->observed_handshake_messages();
1✔
1839

1840
                                  result.test_eq("Server Hello",
2✔
1841
                                                 msgs.at("server_hello")[0],
2✔
1842
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
1843
                                  result.test_eq("Encrypted Extensions",
3✔
1844
                                                 msgs.at("encrypted_extensions")[0],
2✔
1845
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
1846

1847
                                  result.test_eq("Server's entire first flight",
3✔
1848
                                                 ctx->pull_send_buffer(),
2✔
1849
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
1850
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1851

1852
                                  result.confirm("Server can now send application data", ctx->server.is_active());
3✔
1853
                               }),
1✔
1854

1855
            // TODO: The rest of this test vector requires 0-RTT which is not
1856
            //       yet implemented. For now we can only test the server's
1857
            //       ability to acknowledge a session resumption via PSK.
1858
         };
3✔
1859
      }
1✔
1860

1861
      std::vector<Test::Result> hello_retry_request(const VarMap& vars) override {
1✔
1862
         // Fallback RNG is required to for blinding in ECDH with P-256
1863
         auto& fallback_rng = Test::rng();
1✔
1864
         auto rng = std::make_unique<Botan_Tests::Fixed_Output_RNG>(fallback_rng);
1✔
1865

1866
         // 32 - for server hello random
1867
         // 32 - for KeyShare (eph. P-256 key pair)
1868
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1869

1870
         std::unique_ptr<Server_Context> ctx;
1✔
1871

1872
         return {
1✔
1873
            Botan_Tests::CHECK("Receive Client Hello",
1874
                               [&](Test::Result& result) {
1✔
1875
                                  auto add_cookie_and_sort = [&](Botan::TLS::Extensions& exts,
5✔
1876
                                                                 Botan::TLS::Connection_Side side,
1877
                                                                 Botan::TLS::Handshake_Type type) {
1878
                                     if(type == Handshake_Type::HelloRetryRequest) {
4✔
1879
                                        // This cookie needs to be mocked into the HRR since RFC 8448 contains it.
1880
                                        exts.add(new Cookie(vars.get_opt_bin("HelloRetryRequest_Cookie")));
5✔
1881
                                     }
1882
                                     sort_rfc8448_extensions(exts, side, type);
4✔
1883
                                  };
4✔
1884

1885
                                  ctx = std::make_unique<Server_Context>(
2✔
1886
                                     std::move(rng),
1✔
1887
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_hrr_server"),
1✔
1888
                                     vars.get_req_u64("CurrentTimestamp"),
2✔
1889
                                     add_cookie_and_sort,
1890
                                     make_mock_signatures(vars));
3✔
1891
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
1892

1893
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1894

1895
                                  ctx->check_callback_invocations(result,
7✔
1896
                                                                  "client hello received",
1897
                                                                  {"tls_emit_data",
1898
                                                                   "tls_examine_extensions_client_hello",
1899
                                                                   "tls_modify_extensions_hello_retry_request",
1900
                                                                   "tls_inspect_handshake_msg_client_hello",
1901
                                                                   "tls_inspect_handshake_msg_hello_retry_request"});
1902
                               }),
1✔
1903

1904
            Botan_Tests::CHECK("Verify generated Hello Retry Request message",
1905
                               [&](Test::Result& result) {
1✔
1906
                                  result.require("ctx is available", ctx != nullptr);
2✔
1907
                                  result.test_eq("Server's Hello Retry Request record",
2✔
1908
                                                 ctx->pull_send_buffer(),
2✔
1909
                                                 vars.get_req_bin("Record_HelloRetryRequest"));
2✔
1910
                                  result.confirm("TLS handshake not yet finished", !ctx->server.is_active());
2✔
1911
                               }),
1✔
1912

1913
            Botan_Tests::CHECK("Receive updated Client Hello message",
1914
                               [&](Test::Result& result) {
1✔
1915
                                  result.require("ctx is available", ctx != nullptr);
1✔
1916
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_2"));
2✔
1917

1918
                                  ctx->check_callback_invocations(result,
16✔
1919
                                                                  "updated client hello received",
1920
                                                                  {"tls_emit_data",
1921
                                                                   "tls_examine_extensions_client_hello",
1922
                                                                   "tls_modify_extensions_server_hello",
1923
                                                                   "tls_modify_extensions_encrypted_extensions",
1924
                                                                   "tls_modify_extensions_certificate",
1925
                                                                   "tls_sign_message",
1926
                                                                   "tls_generate_ephemeral_key",
1927
                                                                   "tls_ephemeral_key_agreement",
1928
                                                                   "tls_inspect_handshake_msg_client_hello",
1929
                                                                   "tls_inspect_handshake_msg_server_hello",
1930
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
1931
                                                                   "tls_inspect_handshake_msg_certificate",
1932
                                                                   "tls_inspect_handshake_msg_certificate_verify",
1933
                                                                   "tls_inspect_handshake_msg_finished"});
1934
                               }),
1✔
1935

1936
            Botan_Tests::CHECK("Verify generated messages in server's second flight",
1937
                               [&](Test::Result& result) {
1✔
1938
                                  result.require("ctx is available", ctx != nullptr);
2✔
1939
                                  const auto& msgs = ctx->observed_handshake_messages();
1✔
1940

1941
                                  result.test_eq("Server Hello",
2✔
1942
                                                 msgs.at("server_hello")[0],
2✔
1943
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
1944
                                  result.test_eq("Encrypted Extensions",
3✔
1945
                                                 msgs.at("encrypted_extensions")[0],
2✔
1946
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
1947
                                  result.test_eq("Certificate",
3✔
1948
                                                 msgs.at("certificate")[0],
2✔
1949
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
1950
                                  result.test_eq(
3✔
1951
                                     "CertificateVerify",
1952
                                     msgs.at("certificate_verify")[0],
2✔
1953
                                     strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
1954
                                  result.test_eq("Finished",
3✔
1955
                                                 msgs.at("finished")[0],
2✔
1956
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
1957

1958
                                  result.test_eq("Server's entire second flight",
3✔
1959
                                                 ctx->pull_send_buffer(),
2✔
1960
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
1961
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1962
                                  result.confirm("Server could now send application data", ctx->server.is_active());
3✔
1963
                               }),
1✔
1964

1965
            Botan_Tests::CHECK("Receive Client Finished",
1966
                               [&](Test::Result& result) {
1✔
1967
                                  result.require("ctx is available", ctx != nullptr);
1✔
1968
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
1969

1970
                                  ctx->check_callback_invocations(result,
6✔
1971
                                                                  "client finished received",
1972
                                                                  {"tls_inspect_handshake_msg_finished",
1973
                                                                   "tls_current_timestamp",
1974
                                                                   "tls_session_established",
1975
                                                                   "tls_session_activated"});
1976

1977
                                  result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
1978
                               }),
1✔
1979

1980
            Botan_Tests::CHECK("Receive Client close_notify",
1981
                               [&](Test::Result& result) {
1✔
1982
                                  result.require("ctx is available", ctx != nullptr);
1✔
1983
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
1984

1985
                                  ctx->check_callback_invocations(
4✔
1986
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
1987

1988
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
1989
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
1990
                               }),
1✔
1991

1992
            Botan_Tests::CHECK("Expect Server close_notify",
1993
                               [&](Test::Result& result) {
1✔
1994
                                  result.require("ctx is available", ctx != nullptr);
2✔
1995
                                  ctx->server.close();
1✔
1996

1997
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
1998
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
1999
                                  result.test_eq("Server's close notify",
2✔
2000
                                                 ctx->pull_send_buffer(),
2✔
2001
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2002
                               }),
1✔
2003

2004
         };
8✔
2005
      }
1✔
2006

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

2010
         // 32 - for server hello random
2011
         // 32 - for KeyShare (eph. x25519 pair)
2012
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2013

2014
         std::unique_ptr<Server_Context> ctx;
1✔
2015

2016
         return {
1✔
2017
            Botan_Tests::CHECK("Receive Client Hello",
2018
                               [&](Test::Result& result) {
1✔
2019
                                  ctx = std::make_unique<Server_Context>(
2✔
2020
                                     std::move(rng),
1✔
2021
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_client_auth_server"),
1✔
2022
                                     vars.get_req_u64("CurrentTimestamp"),
3✔
2023
                                     sort_rfc8448_extensions,
2024
                                     make_mock_signatures(vars),
1✔
2025
                                     true /* use alternative certificate */);
2✔
2026
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
2027

2028
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2029

2030
                                  ctx->check_callback_invocations(result,
17✔
2031
                                                                  "client hello received",
2032
                                                                  {"tls_emit_data",
2033
                                                                   "tls_examine_extensions_client_hello",
2034
                                                                   "tls_modify_extensions_server_hello",
2035
                                                                   "tls_modify_extensions_encrypted_extensions",
2036
                                                                   "tls_modify_extensions_certificate",
2037
                                                                   "tls_sign_message",
2038
                                                                   "tls_generate_ephemeral_key",
2039
                                                                   "tls_ephemeral_key_agreement",
2040
                                                                   "tls_inspect_handshake_msg_client_hello",
2041
                                                                   "tls_inspect_handshake_msg_server_hello",
2042
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
2043
                                                                   "tls_inspect_handshake_msg_certificate_request",
2044
                                                                   "tls_inspect_handshake_msg_certificate",
2045
                                                                   "tls_inspect_handshake_msg_certificate_verify",
2046
                                                                   "tls_inspect_handshake_msg_finished"});
2047
                               }),
1✔
2048

2049
            Botan_Tests::CHECK(
2050
               "Verify server's generated handshake messages",
2051
               [&](Test::Result& result) {
1✔
2052
                  result.require("ctx is available", ctx != nullptr);
2✔
2053
                  const auto& msgs = ctx->observed_handshake_messages();
1✔
2054

2055
                  result.test_eq("Server Hello",
2✔
2056
                                 msgs.at("server_hello")[0],
2✔
2057
                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
2058
                  result.test_eq("Encrypted Extensions",
3✔
2059
                                 msgs.at("encrypted_extensions")[0],
2✔
2060
                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2061
                  result.test_eq("Certificate Request",
3✔
2062
                                 msgs.at("certificate_request")[0],
2✔
2063
                                 strip_message_header(vars.get_opt_bin("Message_CertificateRequest")));
3✔
2064
                  result.test_eq("Certificate",
3✔
2065
                                 msgs.at("certificate")[0],
2✔
2066
                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
2067
                  result.test_eq("CertificateVerify",
3✔
2068
                                 msgs.at("certificate_verify")[0],
2✔
2069
                                 strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
2070
                  result.test_eq("Finished",
3✔
2071
                                 msgs.at("finished")[0],
2✔
2072
                                 strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2073

2074
                  result.test_eq("Server's entire first flight",
3✔
2075
                                 ctx->pull_send_buffer(),
2✔
2076
                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
2077
                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2078

2079
                  result.confirm("Not yet aware of client's cert chain", ctx->server.peer_cert_chain().empty());
3✔
2080
                  result.confirm("Server could now send application data", ctx->server.is_active());
3✔
2081
               }),
1✔
2082

2083
            Botan_Tests::CHECK("Receive Client's second flight",
2084
                               [&](Test::Result& result) {
1✔
2085
                                  result.require("ctx is available", ctx != nullptr);
1✔
2086
                                  // This encrypted message contains the following messages:
2087
                                  // * client's Certificate message
2088
                                  // * client's Certificate_Verify message
2089
                                  // * client's Finished message
2090
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2091

2092
                                  ctx->check_callback_invocations(result,
11✔
2093
                                                                  "client finished received",
2094
                                                                  {"tls_inspect_handshake_msg_certificate",
2095
                                                                   "tls_inspect_handshake_msg_certificate_verify",
2096
                                                                   "tls_inspect_handshake_msg_finished",
2097
                                                                   "tls_examine_extensions_certificate",
2098
                                                                   "tls_verify_cert_chain",
2099
                                                                   "tls_verify_message",
2100
                                                                   "tls_current_timestamp",
2101
                                                                   "tls_session_established",
2102
                                                                   "tls_session_activated"});
2103

2104
                                  const auto cert_chain = ctx->server.peer_cert_chain();
1✔
2105
                                  result.confirm("Received client's cert chain",
2✔
2106
                                                 !cert_chain.empty() && cert_chain.front() == client_certificate());
2✔
2107

2108
                                  result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2109
                               }),
1✔
2110

2111
            Botan_Tests::CHECK("Receive Client close_notify",
2112
                               [&](Test::Result& result) {
1✔
2113
                                  result.require("ctx is available", ctx != nullptr);
1✔
2114
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2115

2116
                                  ctx->check_callback_invocations(
4✔
2117
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2118

2119
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2120
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
2121
                               }),
1✔
2122

2123
            Botan_Tests::CHECK("Expect Server close_notify",
2124
                               [&](Test::Result& result) {
1✔
2125
                                  result.require("ctx is available", ctx != nullptr);
2✔
2126
                                  ctx->server.close();
1✔
2127

2128
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2129
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2130
                                  result.test_eq("Server's close notify",
2✔
2131
                                                 ctx->pull_send_buffer(),
2✔
2132
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2133
                               }),
1✔
2134

2135
         };
6✔
2136
      }
1✔
2137

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

2141
         // 32 - for server hello random
2142
         // 32 - for KeyShare (eph. x25519 pair)
2143
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2144

2145
         std::unique_ptr<Server_Context> ctx;
1✔
2146

2147
         return {
1✔
2148
            Botan_Tests::CHECK("Receive Client Hello",
2149
                               [&](Test::Result& result) {
1✔
2150
                                  ctx = std::make_unique<Server_Context>(
2✔
2151
                                     std::move(rng),
1✔
2152
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_compat_server"),
1✔
2153
                                     vars.get_req_u64("CurrentTimestamp"),
3✔
2154
                                     sort_rfc8448_extensions,
2155
                                     make_mock_signatures(vars));
3✔
2156
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
2157

2158
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2159

2160
                                  ctx->check_callback_invocations(result,
16✔
2161
                                                                  "client hello received",
2162
                                                                  {"tls_emit_data",
2163
                                                                   "tls_examine_extensions_client_hello",
2164
                                                                   "tls_modify_extensions_server_hello",
2165
                                                                   "tls_modify_extensions_encrypted_extensions",
2166
                                                                   "tls_modify_extensions_certificate",
2167
                                                                   "tls_sign_message",
2168
                                                                   "tls_generate_ephemeral_key",
2169
                                                                   "tls_ephemeral_key_agreement",
2170
                                                                   "tls_inspect_handshake_msg_client_hello",
2171
                                                                   "tls_inspect_handshake_msg_server_hello",
2172
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
2173
                                                                   "tls_inspect_handshake_msg_certificate",
2174
                                                                   "tls_inspect_handshake_msg_certificate_verify",
2175
                                                                   "tls_inspect_handshake_msg_finished"});
2176
                               }),
1✔
2177

2178
            Botan_Tests::CHECK("Verify server's generated handshake messages",
2179
                               [&](Test::Result& result) {
1✔
2180
                                  result.require("ctx is available", ctx != nullptr);
2✔
2181
                                  const auto& msgs = ctx->observed_handshake_messages();
1✔
2182

2183
                                  result.test_eq("Server Hello",
2✔
2184
                                                 msgs.at("server_hello")[0],
2✔
2185
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
2186
                                  result.test_eq("Encrypted Extensions",
3✔
2187
                                                 msgs.at("encrypted_extensions")[0],
2✔
2188
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2189
                                  result.test_eq("Certificate",
3✔
2190
                                                 msgs.at("certificate")[0],
2✔
2191
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
2192
                                  result.test_eq(
3✔
2193
                                     "CertificateVerify",
2194
                                     msgs.at("certificate_verify")[0],
2✔
2195
                                     strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
2196
                                  result.test_eq("Finished",
3✔
2197
                                                 msgs.at("finished")[0],
2✔
2198
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2199

2200
                                  // Those records contain the required Change Cipher Spec message the server must produce for compatibility mode compliance
2201
                                  result.test_eq("Server's entire first flight",
3✔
2202
                                                 ctx->pull_send_buffer(),
2✔
2203
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
2204
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2205

2206
                                  result.confirm("Server could now send application data", ctx->server.is_active());
3✔
2207
                               }),
1✔
2208

2209
            Botan_Tests::CHECK("Receive Client Finished",
2210
                               [&](Test::Result& result) {
1✔
2211
                                  result.require("ctx is available", ctx != nullptr);
1✔
2212
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2213

2214
                                  ctx->check_callback_invocations(result,
6✔
2215
                                                                  "client finished received",
2216
                                                                  {"tls_inspect_handshake_msg_finished",
2217
                                                                   "tls_current_timestamp",
2218
                                                                   "tls_session_established",
2219
                                                                   "tls_session_activated"});
2220

2221
                                  result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2222
                               }),
1✔
2223

2224
            Botan_Tests::CHECK("Receive Client close_notify",
2225
                               [&](Test::Result& result) {
1✔
2226
                                  result.require("ctx is available", ctx != nullptr);
1✔
2227
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2228

2229
                                  ctx->check_callback_invocations(
4✔
2230
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2231

2232
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2233
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
2234
                               }),
1✔
2235

2236
            Botan_Tests::CHECK("Expect Server close_notify",
2237
                               [&](Test::Result& result) {
1✔
2238
                                  result.require("ctx is available", ctx != nullptr);
2✔
2239
                                  ctx->server.close();
1✔
2240

2241
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2242
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2243
                                  result.test_eq("Server's close notify",
2✔
2244
                                                 ctx->pull_send_buffer(),
2✔
2245
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2246
                               }),
1✔
2247

2248
         };
6✔
2249
      }
1✔
2250

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

2254
         // 32 - for server hello random
2255
         // 32 - for KeyShare (eph. x25519 key pair)
2256
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2257

2258
         std::unique_ptr<Server_Context> ctx;
1✔
2259

2260
         return {
1✔
2261
            Botan_Tests::CHECK("Send Client Hello",
2262
                               [&](Test::Result& result) {
1✔
2263
                                  auto sort_our_extensions = [&](Botan::TLS::Extensions& exts,
3✔
2264
                                                                 Botan::TLS::Connection_Side /* side */,
2265
                                                                 Botan::TLS::Handshake_Type type) {
2266
                                     // This is the order of extensions when we first introduced the PSK
2267
                                     // implementation and generated the transcript. To stay compatible
2268
                                     // with the now hard-coded transcript, we pin the extension order.
2269
                                     if(type == Botan::TLS::Handshake_Type::EncryptedExtensions) {
2✔
2270
                                        sort_extensions(exts,
2✔
2271
                                                        {
2272
                                                           Botan::TLS::Extension_Code::SupportedGroups,
2273
                                                           Botan::TLS::Extension_Code::RecordSizeLimit,
2274
                                                           Botan::TLS::Extension_Code::ServerNameIndication,
2275
                                                        });
2276
                                     } else if(type == Botan::TLS::Handshake_Type::ServerHello) {
1✔
2277
                                        sort_extensions(exts,
2✔
2278
                                                        {
2279
                                                           Botan::TLS::Extension_Code::SupportedVersions,
2280
                                                           Botan::TLS::Extension_Code::KeyShare,
2281
                                                           Botan::TLS::Extension_Code::PresharedKey,
2282
                                                        });
2283
                                     }
2284
                                  };
2✔
2285

2286
                                  ctx = std::make_unique<Server_Context>(
2✔
2287
                                     std::move(rng),
1✔
2288
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_psk_dhe", false /* no rfc8448 */),
1✔
2289
                                     vars.get_req_u64("CurrentTimestamp"),
4✔
2290
                                     sort_our_extensions,
2291
                                     make_mock_signatures(vars),
1✔
2292
                                     false,
1✔
2293
                                     std::nullopt,
2294
                                     ExternalPSK(vars.get_req_str("PskIdentity"),
2✔
2295
                                                 vars.get_req_str("PskPRF"),
2✔
2296
                                                 lock(vars.get_req_bin("PskSecret"))));
5✔
2297
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
2298

2299
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2300

2301
                                  ctx->check_callback_invocations(result,
12✔
2302
                                                                  "client hello received",
2303
                                                                  {"tls_emit_data",
2304
                                                                   "tls_examine_extensions_client_hello",
2305
                                                                   "tls_modify_extensions_server_hello",
2306
                                                                   "tls_modify_extensions_encrypted_extensions",
2307
                                                                   "tls_generate_ephemeral_key",
2308
                                                                   "tls_ephemeral_key_agreement",
2309
                                                                   "tls_inspect_handshake_msg_client_hello",
2310
                                                                   "tls_inspect_handshake_msg_server_hello",
2311
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
2312
                                                                   "tls_inspect_handshake_msg_finished"});
2313
                               }),
1✔
2314

2315
            Botan_Tests::CHECK("Verify generated messages in server's first flight",
2316
                               [&](Test::Result& result) {
1✔
2317
                                  result.require("ctx is available", ctx != nullptr);
2✔
2318
                                  const auto& msgs = ctx->observed_handshake_messages();
1✔
2319

2320
                                  result.test_eq("Server Hello",
2✔
2321
                                                 msgs.at("server_hello")[0],
2✔
2322
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
2323
                                  result.test_eq("Encrypted Extensions",
3✔
2324
                                                 msgs.at("encrypted_extensions")[0],
2✔
2325
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2326
                                  result.test_eq("Server Finished",
3✔
2327
                                                 msgs.at("finished")[0],
2✔
2328
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2329

2330
                                  result.test_eq("Server's entire first flight",
3✔
2331
                                                 ctx->pull_send_buffer(),
2✔
2332
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
2333
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2334

2335
                                  result.confirm("Server can now send application data", ctx->server.is_active());
3✔
2336
                               }),
1✔
2337

2338
            Botan_Tests::CHECK("Send Client Finished",
2339
                               [&](Test::Result& result) {
1✔
2340
                                  result.require("ctx is available", ctx != nullptr);
2✔
2341
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2342
                                  result.require("PSK negotiated",
3✔
2343
                                                 ctx->psk_identity_negotiated() == vars.get_req_str("PskIdentity"));
2✔
2344

2345
                                  ctx->check_callback_invocations(result,
6✔
2346
                                                                  "client finished received",
2347
                                                                  {"tls_inspect_handshake_msg_finished",
2348
                                                                   "tls_current_timestamp",
2349
                                                                   "tls_session_established",
2350
                                                                   "tls_session_activated"});
2351
                               }),
1✔
2352

2353
            Botan_Tests::CHECK(
2354
               "Exchange Application Data",
2355
               [&](Test::Result& result) {
1✔
2356
                  result.require("ctx is available", ctx != nullptr);
2✔
2357
                  ctx->server.received_data(vars.get_req_bin("Record_Client_AppData"));
3✔
2358
                  ctx->check_callback_invocations(result, "application data received", {"tls_record_received"});
3✔
2359

2360
                  const auto rcvd = ctx->pull_receive_buffer();
1✔
2361
                  result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Client_AppData"));
3✔
2362
                  result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
1✔
2363

2364
                  ctx->send(vars.get_req_bin("Server_AppData"));
3✔
2365
                  ctx->check_callback_invocations(result, "application data sent", {"tls_emit_data"});
3✔
2366
                  result.test_eq("correct server application data",
3✔
2367
                                 ctx->pull_send_buffer(),
2✔
2368
                                 vars.get_req_bin("Record_Server_AppData"));
3✔
2369
               }),
1✔
2370

2371
            Botan_Tests::CHECK("Terminate Connection",
2372
                               [&](Test::Result& result) {
1✔
2373
                                  result.require("ctx is available", ctx != nullptr);
2✔
2374
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2375

2376
                                  ctx->check_callback_invocations(
4✔
2377
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2378

2379
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2380
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
2381

2382
                                  ctx->server.close();
1✔
2383

2384
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2385
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2386
                                  result.test_eq("Server's close notify",
3✔
2387
                                                 ctx->pull_send_buffer(),
2✔
2388
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2389
                               }),
1✔
2390
         };
6✔
2391
      }
1✔
2392
};
2393

2394
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_client", Test_TLS_RFC8448_Client);
2395
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_server", Test_TLS_RFC8448_Server);
2396

2397
#endif
2398

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