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

randombit / botan / 5123321399

30 May 2023 04:06PM UTC coverage: 92.213% (+0.004%) from 92.209%
5123321399

Pull #3558

github

web-flow
Merge dd72f7389 into 057bcbc35
Pull Request #3558: Add braces around all if/else statements

75602 of 81986 relevant lines covered (92.21%)

11859779.3 hits per line

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

96.63
/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/credentials_manager.h>
26
   #include <botan/ecdsa.h>
27
   #include <botan/hash.h>
28
   #include <botan/rsa.h>
29
   #include <botan/tls_alert.h>
30
   #include <botan/tls_callbacks.h>
31
   #include <botan/tls_client.h>
32
   #include <botan/tls_messages.h>
33
   #include <botan/tls_policy.h>
34
   #include <botan/tls_server.h>
35
   #include <botan/tls_server_info.h>
36
   #include <botan/tls_session.h>
37
   #include <botan/tls_session_manager.h>
38
   #include <botan/tls_version.h>
39
   #include <botan/internal/tls_reader.h>
40

41
   #include <botan/assert.h>
42
   #include <botan/internal/stl_util.h>
43

44
   #include <botan/internal/loadstor.h>
45

46
   #include <botan/data_src.h>
47
   #include <botan/pk_algs.h>
48
   #include <botan/pkcs8.h>
49
#endif
50

51
namespace Botan_Tests {
52

53
#if defined(BOTAN_CAN_RUN_TEST_TLS_RFC8448)
54

55
namespace {
56

57
void add_entropy(Botan_Tests::Fixed_Output_RNG& rng, const std::vector<uint8_t>& bin) {
10✔
58
   rng.add_entropy(bin.data(), bin.size());
20✔
59
}
60

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

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

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

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

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

95
      explicit Padding(const size_t padding_bytes) : m_padding_bytes(padding_bytes) {}
2✔
96

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

101
      bool empty() const override { return m_padding_bytes == 0; }
5✔
102

103
   private:
104
      size_t m_padding_bytes;
105
};
106

107
using namespace Botan;
108
using namespace Botan::TLS;
109

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

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

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

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

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

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

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

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

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

172
      void tls_session_established(const Botan::TLS::Session_Summary&) override {
8✔
173
         count_callback_invocation("tls_session_established");
8✔
174
      }
8✔
175

176
      void tls_session_activated() override {
8✔
177
         count_callback_invocation("tls_session_activated");
8✔
178
         session_activated_called = true;
8✔
179
      }
8✔
180

181
      bool tls_should_persist_resumption_information(const Session&) override {
2✔
182
         count_callback_invocation("tls_should_persist_resumption_information");
2✔
183
         return true;  // should always store the session
2✔
184
      }
185

186
      void tls_verify_cert_chain(const std::vector<Botan::X509_Certificate>& cert_chain,
5✔
187
                                 const std::vector<std::optional<Botan::OCSP::Response>>&,
188
                                 const std::vector<Botan::Certificate_Store*>&,
189
                                 Botan::Usage_Type,
190
                                 std::string_view,
191
                                 const Botan::TLS::Policy&) override {
192
         count_callback_invocation("tls_verify_cert_chain");
5✔
193
         certificate_chain = cert_chain;
5✔
194
      }
5✔
195

196
      std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const override {
×
197
         count_callback_invocation("tls_verify_cert_chain");
×
198
         return std::chrono::milliseconds(0);
×
199
      }
200

201
      std::vector<uint8_t> tls_provide_cert_status(const std::vector<X509_Certificate>& chain,
×
202
                                                   const Certificate_Status_Request& csr) override {
203
         count_callback_invocation("tls_provide_cert_status");
×
204
         return Callbacks::tls_provide_cert_status(chain, csr);
×
205
      }
206

207
      std::vector<uint8_t> tls_sign_message(const Private_Key& key,
5✔
208
                                            RandomNumberGenerator& rng,
209
                                            std::string_view padding,
210
                                            Signature_Format format,
211
                                            const std::vector<uint8_t>& msg) override {
212
         BOTAN_UNUSED(key, rng);
5✔
213
         count_callback_invocation("tls_sign_message");
5✔
214

215
         if(key.algo_name() == "RSA") {
5✔
216
            if(format != Signature_Format::Standard) {
4✔
217
               throw Test_Error("TLS implementation selected unexpected signature format for RSA");
×
218
            }
219

220
            if(padding != "PSSR(SHA-256,MGF1,32)") {
8✔
221
               throw Test_Error("TLS implementation selected unexpected padding for RSA: " + std::string(padding));
×
222
            }
223
         } else if(key.algo_name() == "ECDSA") {
1✔
224
            if(format != Signature_Format::DerSequence) {
1✔
225
               throw Test_Error("TLS implementation selected unexpected signature format for ECDSA");
×
226
            }
227

228
            if(padding != "SHA-256") {
2✔
229
               throw Test_Error("TLS implementation selected unexpected padding for ECDSA: " + std::string(padding));
×
230
            }
231
         } else {
232
            throw Test_Error("TLS implementation trying to sign with unexpected algorithm (" + key.algo_name() + ")");
×
233
         }
234

235
         for(const auto& mock : m_mock_signatures) {
6✔
236
            if(mock.message_to_sign == msg) {
6✔
237
               return mock.signature_to_produce;
5✔
238
            }
239
         }
240

241
         throw Test_Error("TLS implementation produced an unexpected message to be signed: " + Botan::hex_encode(msg));
×
242
      }
243

244
      bool tls_verify_message(const Public_Key& key,
5✔
245
                              std::string_view padding,
246
                              Signature_Format format,
247
                              const std::vector<uint8_t>& msg,
248
                              const std::vector<uint8_t>& sig) override {
249
         count_callback_invocation("tls_verify_message");
5✔
250
         return Callbacks::tls_verify_message(key, padding, format, msg, sig);
5✔
251
      }
252

253
      std::unique_ptr<PK_Key_Agreement_Key> tls_generate_ephemeral_key(
11✔
254
         const std::variant<TLS::Group_Params, DL_Group>& group, RandomNumberGenerator& rng) override {
255
         count_callback_invocation("tls_generate_ephemeral_key");
11✔
256
         return Callbacks::tls_generate_ephemeral_key(group, rng);
11✔
257
      }
258

259
      secure_vector<uint8_t> tls_ephemeral_key_agreement(const std::variant<TLS::Group_Params, DL_Group>& group,
9✔
260
                                                         const PK_Key_Agreement_Key& private_key,
261
                                                         const std::vector<uint8_t>& public_value,
262
                                                         RandomNumberGenerator& rng,
263
                                                         const Policy& policy) override {
264
         count_callback_invocation("tls_ephemeral_key_agreement");
9✔
265
         return Callbacks::tls_ephemeral_key_agreement(group, private_key, public_value, rng, policy);
9✔
266
      }
267

268
      void tls_inspect_handshake_msg(const Handshake_Message& message) override {
72✔
269
         count_callback_invocation("tls_inspect_handshake_msg_" + message.type_string());
144✔
270

271
         try {
72✔
272
            auto serialized_message = message.serialize();
72✔
273

274
            serialized_messages.try_emplace(message.type_string())
146✔
275
               .first->second.emplace_back(std::move(serialized_message));
72✔
276
         } catch(const Not_Implemented&) {
72✔
277
            // TODO: Once the server implementation is finished, this crutch
278
            //       can likely be removed, as all message types will have a
279
            //       serialization method with actual business logic. :o)
280
         }
×
281

282
         return Callbacks::tls_inspect_handshake_msg(message);
72✔
283
      }
284

285
      std::string tls_server_choose_app_protocol(const std::vector<std::string>& client_protos) override {
×
286
         count_callback_invocation("tls_server_choose_app_protocol");
×
287
         return Callbacks::tls_server_choose_app_protocol(client_protos);
×
288
      }
289

290
      void tls_modify_extensions(Botan::TLS::Extensions& exts,
23✔
291
                                 Botan::TLS::Connection_Side side,
292
                                 Botan::TLS::Handshake_Type which_message) override {
293
         count_callback_invocation(std::string("tls_modify_extensions_") + handshake_type_to_string(which_message));
46✔
294
         m_modify_exts(exts, side, which_message);
23✔
295
         Callbacks::tls_modify_extensions(exts, side, which_message);
23✔
296
      }
23✔
297

298
      void tls_examine_extensions(const Botan::TLS::Extensions& extn,
22✔
299
                                  Connection_Side which_side,
300
                                  Botan::TLS::Handshake_Type which_message) override {
301
         count_callback_invocation(std::string("tls_examine_extensions_") + handshake_type_to_string(which_message));
44✔
302
         return Callbacks::tls_examine_extensions(extn, which_side, which_message);
22✔
303
      }
304

305
      std::string tls_peer_network_identity() override {
×
306
         count_callback_invocation("tls_peer_network_identity");
×
307
         return Callbacks::tls_peer_network_identity();
×
308
      }
309

310
      std::chrono::system_clock::time_point tls_current_timestamp() override {
17✔
311
         count_callback_invocation("tls_current_timestamp");
17✔
312
         return m_timestamp;
17✔
313
      }
314

315
      std::vector<uint8_t> pull_send_buffer() { return std::exchange(send_buffer, std::vector<uint8_t>()); }
27✔
316

317
      std::vector<uint8_t> pull_receive_buffer() { return std::exchange(receive_buffer, std::vector<uint8_t>()); }
2✔
318

319
      uint64_t last_received_seq_no() const { return received_seq_no; }
2✔
320

321
      const std::map<std::string, unsigned int>& callback_invocations() const { return m_callback_invocations; }
40✔
322

323
      void reset_callback_invocation_counters() { m_callback_invocations.clear(); }
40✔
324

325
   private:
326
      void count_callback_invocation(const std::string& callback_name) const {
238✔
327
         if(!m_callback_invocations.contains(callback_name)) {
238✔
328
            m_callback_invocations[callback_name] = 0;
225✔
329
         }
330

331
         m_callback_invocations[callback_name]++;
238✔
332
      }
238✔
333

334
   public:
335
      bool session_activated_called;
336

337
      std::vector<Botan::X509_Certificate> certificate_chain;
338
      std::map<std::string, std::vector<std::vector<uint8_t>>> serialized_messages;
339

340
   private:
341
      std::vector<uint8_t> send_buffer;
342
      std::vector<uint8_t> receive_buffer;
343
      uint64_t received_seq_no;
344
      Modify_Exts_Fn m_modify_exts;
345
      std::vector<MockSignature> m_mock_signatures;
346
      std::chrono::system_clock::time_point m_timestamp;
347

348
      mutable std::map<std::string, unsigned int> m_callback_invocations;
349
};
350

351
class Test_Credentials : public Botan::Credentials_Manager {
352
   public:
353
      explicit Test_Credentials(bool use_alternative_server_certificate) :
10✔
354
            m_alternative_server_certificate(use_alternative_server_certificate) {
10✔
355
         Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/server_key.pem"));
20✔
356
         m_server_private_key.reset(Botan::PKCS8::load_key(in).release());
10✔
357

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

364
         m_client_private_key.reset(create_private_key("RSA", Test::rng(), "1024").release());
20✔
365
      }
10✔
366

367
      std::vector<Botan::X509_Certificate> cert_chain(const std::vector<std::string>& cert_key_types,
5✔
368
                                                      const std::vector<AlgorithmIdentifier>& cert_signature_schemes,
369
                                                      const std::string& type,
370
                                                      const std::string& context) override {
371
         BOTAN_UNUSED(cert_key_types, cert_signature_schemes, context);
5✔
372
         return {(type == "tls-client")
5✔
373
                    ? client_certificate()
374
                    : ((m_alternative_server_certificate) ? alternative_server_certificate() : server_certificate())};
10✔
375
      }
376

377
      std::shared_ptr<Botan::Private_Key> private_key_for(const Botan::X509_Certificate& cert,
5✔
378
                                                          const std::string& type,
379
                                                          const std::string& context) override {
380
         BOTAN_UNUSED(cert, context);
5✔
381

382
         if(type == "tls-client") {
5✔
383
            return m_client_private_key;
1✔
384
         }
385

386
         if(m_alternative_server_certificate) {
4✔
387
            return m_bogus_alternative_server_private_key;
1✔
388
         }
389

390
         return m_server_private_key;
3✔
391
      }
392

393
   private:
394
      bool m_alternative_server_certificate;
395
      std::shared_ptr<Private_Key> m_client_private_key;
396
      std::shared_ptr<Private_Key> m_bogus_alternative_server_private_key;
397
      std::shared_ptr<Private_Key> m_server_private_key;
398
};
399

400
class RFC8448_Text_Policy : public Botan::TLS::Text_Policy {
10✔
401
   private:
402
      Botan::TLS::Text_Policy read_policy(const std::string& policy_file) {
10✔
403
         const std::string fspath = Test::data_file("tls-policy/" + policy_file + ".txt");
20✔
404

405
         std::ifstream is(fspath.c_str());
10✔
406
         if(!is.good()) {
10✔
407
            throw Test_Error("Missing policy file " + fspath);
×
408
         }
409

410
         return Botan::TLS::Text_Policy(is);
10✔
411
      }
20✔
412

413
   public:
414
      RFC8448_Text_Policy(const std::string& policy_file) : Botan::TLS::Text_Policy(read_policy(policy_file)) {}
10✔
415

416
      std::vector<Botan::TLS::Signature_Scheme> allowed_signature_schemes() const override {
11✔
417
         // We extend the allowed signature schemes with algorithms that we don't
418
         // actually support. The nature of the RFC 8448 test forces us to generate
419
         // bit-compatible TLS messages. Unfortunately, the test data offers all
420
         // those algorithms in its Client Hellos.
421
         return {
11✔
422
            Botan::TLS::Signature_Scheme::ECDSA_SHA256,
423
            Botan::TLS::Signature_Scheme::ECDSA_SHA384,
424
            Botan::TLS::Signature_Scheme::ECDSA_SHA512,
425
            Botan::TLS::Signature_Scheme::ECDSA_SHA1,  // not actually supported
426
            Botan::TLS::Signature_Scheme::RSA_PSS_SHA256,
427
            Botan::TLS::Signature_Scheme::RSA_PSS_SHA384,
428
            Botan::TLS::Signature_Scheme::RSA_PSS_SHA512,
429
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA256,
430
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA384,
431
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA512,
432
            Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA1,  // not actually supported
433
            Botan::TLS::Signature_Scheme(0x0402),          // DSA_SHA256, not actually supported
434
            Botan::TLS::Signature_Scheme(0x0502),          // DSA_SHA384, not actually supported
435
            Botan::TLS::Signature_Scheme(0x0602),          // DSA_SHA512, not actually supported
436
            Botan::TLS::Signature_Scheme(0x0202),          // DSA_SHA1, not actually supported
437
         };
11✔
438
      }
439

440
      // Overriding the key exchange group selection to favour the server's key
441
      // exchange group preference. This is required to enforce a Hello Retry Request
442
      // when testing RFC 8448 5. from the server side.
443
      Named_Group choose_key_exchange_group(const std::vector<Group_Params>& supported_by_peer,
6✔
444
                                            const std::vector<Group_Params>& offered_by_peer) const override {
445
         BOTAN_UNUSED(offered_by_peer);
6✔
446

447
         const auto supported_by_us = key_exchange_groups();
6✔
448
         const auto selected_group =
6✔
449
            std::find_if(supported_by_us.begin(), supported_by_us.end(), [&](const auto group) {
6✔
450
               return value_exists(supported_by_peer, group);
12✔
451
            });
452

453
         return selected_group != supported_by_us.end() ? *selected_group : Named_Group::NONE;
6✔
454
      }
6✔
455
};
456

457
/**
458
 * In-Memory Session Manager that stores sessions verbatim, without encryption.
459
 * Therefor it is not dependent on a random number generator and can easily be
460
 * instrumented for test inspection.
461
 */
462
class RFC8448_Session_Manager : public Botan::TLS::Session_Manager {
463
   private:
464
      decltype(auto) find_by_handle(const Session_Handle& handle) {
2✔
465
         return [=](const Session_with_Handle& session) {
21✔
466
            if(session.handle.id().has_value() && handle.id().has_value() &&
4✔
467
               session.handle.id().value() == handle.id().value()) {
2✔
468
               return true;
469
            }
470
            if(session.handle.ticket().has_value() && handle.ticket().has_value() &&
8✔
471
               session.handle.ticket().value() == handle.ticket().value()) {
10✔
472
               return true;
2✔
473
            }
474
            return false;
475
         };
2✔
476
      }
477

478
   public:
479
      RFC8448_Session_Manager() : Session_Manager(Test::rng_as_shared()) {}
20✔
480

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

483
      void store(const Session& session, const Session_Handle& handle) override {
4✔
484
         m_sessions.push_back({session, handle});
4✔
485
      }
4✔
486

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

492
         if(m_sessions.size() != 1) {
1✔
493
            throw Botan_Tests::Test_Error("No mocked session handle available; Test bug?");
×
494
         }
495

496
         const auto& [mocked_session, handle] = m_sessions.front();
1✔
497
         if(mocked_session.master_secret() != session.master_secret()) {
1✔
498
            throw Botan_Tests::Test_Error("Generated session object does not match the expected mock");
×
499
         }
500

501
         return handle;
1✔
502
      }
503

504
      std::optional<Session> retrieve_one(const Session_Handle& handle) override {
1✔
505
         auto itr = std::find_if(m_sessions.begin(), m_sessions.end(), find_by_handle(handle));
1✔
506
         if(itr == m_sessions.end()) {
1✔
507
            return std::nullopt;
×
508
         } else {
509
            return itr->session;
2✔
510
         }
511
      }
512

513
      std::vector<Session_with_Handle> find_some(const Server_Information& info, const size_t) override {
5✔
514
         std::vector<Session_with_Handle> found_sessions;
5✔
515
         for(const auto& [session, handle] : m_sessions) {
6✔
516
            if(session.server_info() == info) {
1✔
517
               found_sessions.emplace_back(Session_with_Handle{session, handle});
2✔
518
            }
519
         }
520

521
         return found_sessions;
5✔
522
      }
×
523

524
      size_t remove(const Session_Handle& handle) override {
1✔
525
         // TODO: C++20 allows to simply implement the entire method like:
526
         //
527
         //   return std::erase_if(m_sessions, find_by_handle(handle));
528
         //
529
         // Unfortunately, at the time of this writing Android NDK shipped with
530
         // a std::erase_if that returns void.
531
         auto rm_itr = std::remove_if(m_sessions.begin(), m_sessions.end(), find_by_handle(handle));
1✔
532

533
         const auto elements_being_removed = std::distance(rm_itr, m_sessions.end());
1✔
534
         m_sessions.erase(rm_itr);
1✔
535
         return elements_being_removed;
1✔
536
      }
537

538
      size_t remove_all() override {
×
539
         const auto sessions = m_sessions.size();
×
540
         m_sessions.clear();
×
541
         return sessions;
×
542
      }
543

544
   private:
545
      std::vector<Session_with_Handle> m_sessions;
546
};
547

548
/**
549
 * This steers the TLS client handle and is the central entry point for the
550
 * test cases to interact with the TLS 1.3 implementation.
551
 *
552
 * Note: This class is abstract to be subclassed for both client and server tests.
553
 */
554
class TLS_Context {
555
   protected:
556
      TLS_Context(std::shared_ptr<Botan::RandomNumberGenerator> rng_in,
10✔
557
                  std::shared_ptr<const RFC8448_Text_Policy> policy,
558
                  Modify_Exts_Fn modify_exts_cb,
559
                  std::vector<MockSignature> mock_signatures,
560
                  uint64_t timestamp,
561
                  std::optional<std::pair<Session, Session_Ticket>> session_and_ticket,
562
                  bool use_alternative_server_certificate) :
10✔
563
            m_callbacks(std::make_shared<Test_TLS_13_Callbacks>(
10✔
564
               std::move(modify_exts_cb), std::move(mock_signatures), timestamp)),
10✔
565
            m_creds(std::make_shared<Test_Credentials>(use_alternative_server_certificate)),
10✔
566
            m_rng(std::move(rng_in)),
10✔
567
            m_session_mgr(std::make_shared<RFC8448_Session_Manager>()),
568
            m_policy(std::move(policy)) {
20✔
569
         if(session_and_ticket.has_value()) {
10✔
570
            m_session_mgr->store(std::get<Session>(session_and_ticket.value()),
12✔
571
                                 std::get<Session_Ticket>(session_and_ticket.value()));
3✔
572
         }
573
      }
10✔
574

575
   public:
576
      virtual ~TLS_Context() = default;
50✔
577

578
      TLS_Context(TLS_Context&) = delete;
579
      TLS_Context& operator=(const TLS_Context&) = delete;
580

581
      TLS_Context(TLS_Context&&) = delete;
582
      TLS_Context& operator=(TLS_Context&&) = delete;
583

584
      std::vector<uint8_t> pull_send_buffer() { return m_callbacks->pull_send_buffer(); }
27✔
585

586
      std::vector<uint8_t> pull_receive_buffer() { return m_callbacks->pull_receive_buffer(); }
2✔
587

588
      uint64_t last_received_seq_no() const { return m_callbacks->last_received_seq_no(); }
2✔
589

590
      /**
591
       * Checks that all of the listed callbacks were called at least once, no other
592
       * callbacks were called in addition to the expected ones. After the checks are
593
       * done, the callback invocation counters are reset.
594
       */
595
      void check_callback_invocations(Test::Result& result,
40✔
596
                                      const std::string& context,
597
                                      const std::vector<std::string>& callback_names) {
598
         const auto& invokes = m_callbacks->callback_invocations();
40✔
599
         for(const auto& cbn : callback_names) {
258✔
600
            result.confirm(cbn + " was invoked (Context: " + context + ")",
872✔
601
                           invokes.contains(cbn) && invokes.at(cbn) > 0);
218✔
602
         }
603

604
         for(const auto& invoke : invokes) {
258✔
605
            if(invoke.second == 0) {
218✔
606
               continue;
×
607
            }
608
            result.confirm(
436✔
609
               invoke.first + " was expected (Context: " + context + ")",
436✔
610
               std::find(callback_names.cbegin(), callback_names.cend(), invoke.first) != callback_names.cend());
436✔
611
         }
612

613
         m_callbacks->reset_callback_invocation_counters();
40✔
614
      }
40✔
615

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

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

620
      decltype(auto) observed_handshake_messages() const { return m_callbacks->serialized_messages; }
5✔
621

622
      /**
623
       * Send application data through the secure channel
624
       */
625
      virtual void send(const std::vector<uint8_t>& data) = 0;
626

627
   protected:
628
      std::shared_ptr<Test_TLS_13_Callbacks> m_callbacks;
629
      std::shared_ptr<Test_Credentials> m_creds;
630

631
      std::shared_ptr<Botan::RandomNumberGenerator> m_rng;
632
      std::shared_ptr<RFC8448_Session_Manager> m_session_mgr;
633
      std::shared_ptr<const RFC8448_Text_Policy> m_policy;
634
};
635

636
class Client_Context : public TLS_Context {
637
   public:
638
      Client_Context(std::shared_ptr<Botan::RandomNumberGenerator> rng_in,
5✔
639
                     std::shared_ptr<const RFC8448_Text_Policy> policy,
640
                     uint64_t timestamp,
641
                     Modify_Exts_Fn modify_exts_cb,
642
                     std::optional<std::pair<Session, Session_Ticket>> session_and_ticket = std::nullopt,
643
                     std::vector<MockSignature> mock_signatures = {}) :
5✔
644
            TLS_Context(std::move(rng_in),
5✔
645
                        std::move(policy),
5✔
646
                        std::move(modify_exts_cb),
5✔
647
                        std::move(mock_signatures),
5✔
648
                        timestamp,
649
                        std::move(session_and_ticket),
5✔
650
                        false),
651
            client(m_callbacks,
20✔
652
                   m_session_mgr,
5✔
653
                   m_creds,
5✔
654
                   m_policy,
5✔
655
                   m_rng,
5✔
656
                   Botan::TLS::Server_Information("server"),
10✔
657
                   Botan::TLS::Protocol_Version::TLS_V13) {}
21✔
658

659
      void send(const std::vector<uint8_t>& data) override { client.send(data.data(), data.size()); }
1✔
660

661
      Botan::TLS::Client client;
662
};
663

664
class Server_Context : public TLS_Context {
665
   public:
666
      Server_Context(std::shared_ptr<Botan::RandomNumberGenerator> rng,
5✔
667
                     std::shared_ptr<const RFC8448_Text_Policy> policy,
668
                     uint64_t timestamp,
669
                     Modify_Exts_Fn modify_exts_cb,
670
                     std::vector<MockSignature> mock_signatures,
671
                     bool use_alternative_server_certificate = false,
672
                     std::optional<std::pair<Session, Session_Ticket>> session_and_ticket = std::nullopt) :
5✔
673
            TLS_Context(std::move(rng),
5✔
674
                        std::move(policy),
5✔
675
                        std::move(modify_exts_cb),
5✔
676
                        std::move(mock_signatures),
5✔
677
                        timestamp,
678
                        std::move(session_and_ticket),
5✔
679
                        use_alternative_server_certificate),
680
            server(m_callbacks, m_session_mgr, m_creds, m_policy, m_rng, false /* DTLS NYI */) {}
37✔
681

682
      void send(const std::vector<uint8_t>& data) override { server.send(data.data(), data.size()); }
1✔
683

684
      Botan::TLS::Server server;
685
};
686

687
/**
688
 * Because of the nature of the RFC 8448 test data we need to produce bit-compatible
689
 * TLS messages. Hence we sort the generated TLS extensions exactly as expected.
690
 */
691
void sort_client_extensions(Botan::TLS::Extensions& exts, Botan::TLS::Connection_Side side) {
6✔
692
   if(side == Botan::TLS::Connection_Side::Client) {
6✔
693
      const std::vector<Botan::TLS::Extension_Code> expected_order = {
6✔
694
         Botan::TLS::Extension_Code::ServerNameIndication,
695
         Botan::TLS::Extension_Code::SafeRenegotiation,
696
         Botan::TLS::Extension_Code::SupportedGroups,
697
         Botan::TLS::Extension_Code::SessionTicket,
698
         Botan::TLS::Extension_Code::KeyShare,
699
         Botan::TLS::Extension_Code::EarlyData,
700
         Botan::TLS::Extension_Code::SupportedVersions,
701
         Botan::TLS::Extension_Code::SignatureAlgorithms,
702
         Botan::TLS::Extension_Code::Cookie,
703
         Botan::TLS::Extension_Code::PskKeyExchangeModes,
704
         Botan::TLS::Extension_Code::RecordSizeLimit,
705
         Padding::static_type(),
706
         Botan::TLS::Extension_Code::PresharedKey,
707
      };
6✔
708

709
      for(const auto ext_type : expected_order) {
84✔
710
         auto ext = exts.take(ext_type);
78✔
711
         if(ext != nullptr) {
78✔
712
            exts.add(std::move(ext));
108✔
713
         }
714
      }
78✔
715
   }
6✔
716
}
6✔
717

718
/**
719
 * Because of the nature of the RFC 8448 test data we need to produce bit-compatible
720
 * TLS messages. Hence we sort the generated TLS extensions exactly as expected.
721
 */
722
void sort_server_extensions(Botan::TLS::Extensions& exts,
16✔
723
                            Botan::TLS::Connection_Side side,
724
                            Botan::TLS::Handshake_Type /*type*/) {
725
   if(side == Botan::TLS::Connection_Side::Server) {
16✔
726
      const std::vector<Botan::TLS::Extension_Code> expected_order = {
16✔
727
         Botan::TLS::Extension_Code::SupportedGroups,
728
         Botan::TLS::Extension_Code::KeyShare,
729
         Botan::TLS::Extension_Code::Cookie,
730
         Botan::TLS::Extension_Code::SupportedVersions,
731
         Botan::TLS::Extension_Code::SignatureAlgorithms,
732
         Botan::TLS::Extension_Code::RecordSizeLimit,
733
         Botan::TLS::Extension_Code::ServerNameIndication,
734
         Botan::TLS::Extension_Code::EarlyData,
735
      };
16✔
736

737
      for(const auto ext_type : expected_order) {
144✔
738
         auto ext = exts.take(ext_type);
128✔
739
         if(ext != nullptr) {
128✔
740
            exts.add(std::move(ext));
60✔
741
         }
742
      }
128✔
743
   }
16✔
744
}
16✔
745

746
void add_renegotiation_extension(Botan::TLS::Extensions& exts) {
5✔
747
   // Renegotiation is not possible in TLS 1.3. Nevertheless, RFC 8448 requires
748
   // to add this to the Client Hello for reasons.
749
   exts.add(new Renegotiation_Extension());
5✔
750
}
5✔
751

752
void add_early_data_indication(Botan::TLS::Extensions& exts) { exts.add(new Botan::TLS::EarlyDataIndication()); }
1✔
753

754
std::vector<uint8_t> strip_message_header(const std::vector<uint8_t>& msg) {
22✔
755
   BOTAN_ASSERT_NOMSG(msg.size() >= 4);
22✔
756
   return {msg.begin() + 4, msg.end()};
22✔
757
}
758

759
std::vector<MockSignature> make_mock_signatures(const VarMap& vars) {
6✔
760
   std::vector<MockSignature> result;
6✔
761

762
   auto mock = [&](const std::string& msg, const std::string& sig) {
18✔
763
      if(vars.has_key(msg) && vars.has_key(sig)) {
31✔
764
         result.push_back({vars.get_opt_bin(msg), vars.get_opt_bin(sig)});
7✔
765
      }
766
   };
12✔
767

768
   mock("Server_MessageToSign", "Server_MessageSignature");
12✔
769
   mock("Client_MessageToSign", "Client_MessageSignature");
12✔
770

771
   return result;
6✔
772
}
×
773

774
}  // namespace
775

776
/**
777
 * Traffic transcripts and supporting data for the TLS RFC 8448 and TLS policy
778
 * configuration is kept in data files (accessible via `Test:::data_file()`).
779
 *
780
 * tls_13_rfc8448/transcripts.vec
781
 *   The record transcripts and RNG outputs as defined/required in RFC 8448 in
782
 *   Botan's Text_Based_Test vector format. Data from each RFC 8448 section is
783
 *   placed in a sub-section of the *.vec file. Each of those sections needs a
784
 *   specific test case implementation that is dispatched in `run_one_test()`.
785
 *
786
 * tls_13_rfc8448/client_certificate.pem
787
 *   The client certificate provided in RFC 8448 used to perform client auth.
788
 *   Note that RFC 8448 _does not_ provide the associated private key but only
789
 *   the resulting signature in the client's CertificateVerify message.
790
 *
791
 * tls_13_rfc8448/server_certificate.pem
792
 * tls_13_rfc8448/server_key.pem
793
 *   The server certificate and its associated private key.
794
 *
795
 * tls_13_rfc8448/server_certificate_client_auth.pem
796
 *   The server certificate used in the Client Authentication test case.
797
 *
798
 * tls-policy/rfc8448_*.txt
799
 *   Each RFC 8448 section test required a slightly adapted Botan TLS policy
800
 *   to enable/disable certain features under test.
801
 *
802
 * While the test cases are split into Client-side and Server-side tests, the
803
 * transcript data is reused. See the concrete implementations of the abstract
804
 * Test_TLS_RFC8448 test class.
805
 */
806
class Test_TLS_RFC8448 : public Text_Based_Test {
807
   protected:
808
      virtual std::vector<Test::Result> simple_1_rtt(const VarMap& vars) = 0;
809
      virtual std::vector<Test::Result> resumed_handshake_with_0_rtt(const VarMap& vars) = 0;
810
      virtual std::vector<Test::Result> hello_retry_request(const VarMap& vars) = 0;
811
      virtual std::vector<Test::Result> client_authentication(const VarMap& vars) = 0;
812
      virtual std::vector<Test::Result> middlebox_compatibility(const VarMap& vars) = 0;
813

814
      virtual std::string side() const = 0;
815

816
   public:
817
      Test_TLS_RFC8448() :
2✔
818
            Text_Based_Test("tls_13_rfc8448/transcripts.vec",
819
                            // mandatory data fields
820
                            "Client_RNG_Pool,"
821
                            "Server_RNG_Pool,"
822
                            "CurrentTimestamp,"
823
                            "Record_ClientHello_1,"
824
                            "Record_ServerHello,"
825
                            "Record_ServerHandshakeMessages,"
826
                            "Record_ClientFinished,"
827
                            "Record_Client_CloseNotify,"
828
                            "Record_Server_CloseNotify",
829
                            // optional data fields
830
                            "Message_ServerHello,"
831
                            "Message_EncryptedExtensions,"
832
                            "Message_CertificateRequest,"
833
                            "Message_Server_Certificate,"
834
                            "Message_Server_CertificateVerify,"
835
                            "Message_Server_Finished,"
836
                            "Record_HelloRetryRequest,"
837
                            "Record_ClientHello_2,"
838
                            "Record_NewSessionTicket,"
839
                            "Client_AppData,"
840
                            "Record_Client_AppData,"
841
                            "Server_AppData,"
842
                            "Record_Server_AppData,"
843
                            "Client_EarlyAppData,"
844
                            "Record_Client_EarlyAppData,"
845
                            "SessionTicket,"
846
                            "Client_SessionData,"
847
                            "Server_MessageToSign,"
848
                            "Server_MessageSignature,"
849
                            "Client_MessageToSign,"
850
                            "Client_MessageSignature,"
851
                            "HelloRetryRequest_Cookie") {}
8✔
852

853
      Test::Result run_one_test(const std::string& header, const VarMap& vars) override {
10✔
854
         if(header == "Simple_1RTT_Handshake") {
10✔
855
            return Test::Result("Simple 1-RTT (" + side() + " side)", simple_1_rtt(vars));
4✔
856
         } else if(header == "Resumed_0RTT_Handshake") {
8✔
857
            return Test::Result("Resumption with 0-RTT data (" + side() + " side)", resumed_handshake_with_0_rtt(vars));
4✔
858
         } else if(header == "HelloRetryRequest_Handshake") {
6✔
859
            return Test::Result("Handshake involving Hello Retry Request (" + side() + " side)",
4✔
860
                                hello_retry_request(vars));
6✔
861
         } else if(header == "Client_Authentication_Handshake") {
4✔
862
            return Test::Result("Client Authentication (" + side() + " side)", client_authentication(vars));
4✔
863
         } else if(header == "Middlebox_Compatibility_Mode") {
2✔
864
            return Test::Result("Middlebox Compatibility Mode (" + side() + " side)", middlebox_compatibility(vars));
4✔
865
         } else {
866
            return Test::Result::Failure("test dispatcher", "unknown sub-test: " + header);
×
867
         }
868
      }
869
};
870

871
class Test_TLS_RFC8448_Client : public Test_TLS_RFC8448 {
1✔
872
   private:
873
      std::string side() const override { return "Client"; }
5✔
874

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

878
         // 32 - for client hello random
879
         // 32 - for KeyShare (eph. x25519 key pair)
880
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
881

882
         auto add_extensions_and_sort = [](Botan::TLS::Extensions& exts,
2✔
883
                                           Botan::TLS::Connection_Side side,
884
                                           Botan::TLS::Handshake_Type which_message) {
885
            if(which_message == Handshake_Type::ClientHello) {
1✔
886
               // For some reason, presumably checking compatibility, the RFC 8448 Client
887
               // Hello includes a (TLS 1.2) Session_Ticket extension. We don't normally add
888
               // this obsoleted extension in a TLS 1.3 client.
889
               exts.add(new Botan::TLS::Session_Ticket_Extension());
1✔
890

891
               add_renegotiation_extension(exts);
1✔
892
               sort_client_extensions(exts, side);
1✔
893
            }
894
         };
1✔
895

896
         std::unique_ptr<Client_Context> ctx;
1✔
897

898
         return {
1✔
899
            Botan_Tests::CHECK(
900
               "Client Hello",
901
               [&](Test::Result& result) {
1✔
902
                  ctx = std::make_unique<Client_Context>(rng,
3✔
903
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
904
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
905
                                                         add_extensions_and_sort);
2✔
906

907
                  result.confirm("client not closed", !ctx->client.is_closed());
2✔
908
                  ctx->check_callback_invocations(result,
7✔
909
                                                  "client hello prepared",
910
                                                  {
911
                                                     "tls_emit_data",
912
                                                     "tls_inspect_handshake_msg_client_hello",
913
                                                     "tls_modify_extensions_client_hello",
914
                                                     "tls_generate_ephemeral_key",
915
                                                     "tls_current_timestamp",
916
                                                  });
917

918
                  result.test_eq("TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
919
               }),
1✔
920

921
            Botan_Tests::CHECK(
922
               "Server Hello",
923
               [&](Test::Result& result) {
1✔
924
                  result.require("ctx is available", ctx != nullptr);
1✔
925
                  const auto server_hello = vars.get_req_bin("Record_ServerHello");
1✔
926
                  // splitting the input data to test partial reads
927
                  const std::vector<uint8_t> server_hello_a(server_hello.begin(), server_hello.begin() + 20);
1✔
928
                  const std::vector<uint8_t> server_hello_b(server_hello.begin() + 20, server_hello.end());
1✔
929

930
                  ctx->client.received_data(server_hello_a);
1✔
931
                  ctx->check_callback_invocations(result, "server hello partially received", {});
2✔
932

933
                  ctx->client.received_data(server_hello_b);
1✔
934
                  ctx->check_callback_invocations(result,
5✔
935
                                                  "server hello received",
936
                                                  {"tls_inspect_handshake_msg_server_hello",
937
                                                   "tls_examine_extensions_server_hello",
938
                                                   "tls_ephemeral_key_agreement"});
939

940
                  result.confirm("client is not yet active", !ctx->client.is_active());
3✔
941
               }),
3✔
942

943
            Botan_Tests::CHECK(
944
               "Server HS messages .. Client Finished",
945
               [&](Test::Result& result) {
1✔
946
                  result.require("ctx is available", ctx != nullptr);
3✔
947
                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
948

949
                  ctx->check_callback_invocations(result,
14✔
950
                                                  "encrypted handshake messages received",
951
                                                  {"tls_inspect_handshake_msg_encrypted_extensions",
952
                                                   "tls_inspect_handshake_msg_certificate",
953
                                                   "tls_inspect_handshake_msg_certificate_verify",
954
                                                   "tls_inspect_handshake_msg_finished",
955
                                                   "tls_examine_extensions_encrypted_extensions",
956
                                                   "tls_examine_extensions_certificate",
957
                                                   "tls_emit_data",
958
                                                   "tls_current_timestamp",
959
                                                   "tls_session_established",
960
                                                   "tls_session_activated",
961
                                                   "tls_verify_cert_chain",
962
                                                   "tls_verify_message"});
963
                  result.require("certificate exists", !ctx->certs_verified().empty());
1✔
964
                  result.require("correct certificate", ctx->certs_verified().front() == server_certificate());
2✔
965
                  result.require("client is active", ctx->client.is_active());
1✔
966

967
                  result.test_eq(
3✔
968
                     "correct handshake finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
3✔
969
               }),
1✔
970

971
            Botan_Tests::CHECK("Post-Handshake: NewSessionTicket",
972
                               [&](Test::Result& result) {
1✔
973
                                  result.require("ctx is available", ctx != nullptr);
1✔
974
                                  result.require("no sessions so far", ctx->stored_sessions().empty());
1✔
975
                                  ctx->client.received_data(vars.get_req_bin("Record_NewSessionTicket"));
2✔
976

977
                                  ctx->check_callback_invocations(result,
5✔
978
                                                                  "new session ticket received",
979
                                                                  {"tls_examine_extensions_new_session_ticket",
980
                                                                   "tls_should_persist_resumption_information",
981
                                                                   "tls_current_timestamp"});
982
                                  if(result.test_eq("session was stored", ctx->stored_sessions().size(), 1)) {
2✔
983
                                     const auto& [stored_session, stored_handle] = ctx->stored_sessions().front();
1✔
984
                                     result.require("session handle contains a ticket",
2✔
985
                                                    stored_handle.ticket().has_value());
1✔
986
                                     result.test_is_eq("session was serialized as expected",
3✔
987
                                                       Botan::unlock(stored_session.DER_encode()),
4✔
988
                                                       vars.get_req_bin("Client_SessionData"));
3✔
989
                                  }
990
                               }),
1✔
991

992
            Botan_Tests::CHECK("Send Application Data",
993
                               [&](Test::Result& result) {
1✔
994
                                  result.require("ctx is available", ctx != nullptr);
2✔
995
                                  ctx->send(vars.get_req_bin("Client_AppData"));
3✔
996

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

999
                                  result.test_eq("correct client application data",
3✔
1000
                                                 ctx->pull_send_buffer(),
2✔
1001
                                                 vars.get_req_bin("Record_Client_AppData"));
2✔
1002
                               }),
1✔
1003

1004
            Botan_Tests::CHECK(
1005
               "Receive Application Data",
1006
               [&](Test::Result& result) {
1✔
1007
                  result.require("ctx is available", ctx != nullptr);
1✔
1008
                  ctx->client.received_data(vars.get_req_bin("Record_Server_AppData"));
2✔
1009

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

1012
                  const auto rcvd = ctx->pull_receive_buffer();
1✔
1013
                  result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Server_AppData"));
3✔
1014
                  result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(1));
2✔
1015
               }),
1✔
1016

1017
            Botan_Tests::CHECK("Close Connection",
1018
                               [&](Test::Result& result) {
1✔
1019
                                  result.require("ctx is available", ctx != nullptr);
2✔
1020
                                  ctx->client.close();
1✔
1021

1022
                                  result.test_eq("close payload",
2✔
1023
                                                 ctx->pull_send_buffer(),
2✔
1024
                                                 vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1025
                                  ctx->check_callback_invocations(result, "CLOSE_NOTIFY sent", {"tls_emit_data"});
3✔
1026

1027
                                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1028
                                  ctx->check_callback_invocations(
4✔
1029
                                     result, "CLOSE_NOTIFY received", {"tls_alert", "tls_peer_closed_connection"});
1030

1031
                                  result.confirm("connection is closed", ctx->client.is_closed());
2✔
1032
                               }),
1✔
1033
         };
8✔
1034
      }
2✔
1035

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

1039
         // 32 - for client hello random
1040
         // 32 - for KeyShare (eph. x25519 key pair)
1041
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1042

1043
         auto add_extensions_and_sort = [](Botan::TLS::Extensions& exts,
2✔
1044
                                           Botan::TLS::Connection_Side side,
1045
                                           Botan::TLS::Handshake_Type which_message) {
1046
            if(which_message == Handshake_Type::ClientHello) {
1✔
1047
               exts.add(new Padding(87));
1✔
1048

1049
               add_renegotiation_extension(exts);
1✔
1050

1051
               // TODO: Implement early data support and remove this 'hack'.
1052
               //
1053
               // Currently, the production implementation will never add this
1054
               // extension even if the resumed session would allow early data.
1055
               add_early_data_indication(exts);
1✔
1056
               sort_client_extensions(exts, side);
1✔
1057
            }
1058
         };
1✔
1059

1060
         std::unique_ptr<Client_Context> ctx;
1✔
1061

1062
         return {
1✔
1063
            Botan_Tests::CHECK(
1064
               "Client Hello",
1065
               [&](Test::Result& result) {
1✔
1066
                  ctx = std::make_unique<Client_Context>(
3✔
1067
                     std::move(rng),
1✔
1068
                     std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
1069
                     vars.get_req_u64("CurrentTimestamp"),
4✔
1070
                     add_extensions_and_sort,
1✔
1071
                     std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
1072
                               Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1073

1074
                  result.confirm("client not closed", !ctx->client.is_closed());
2✔
1075
                  ctx->check_callback_invocations(result,
7✔
1076
                                                  "client hello prepared",
1077
                                                  {
1078
                                                     "tls_emit_data",
1079
                                                     "tls_inspect_handshake_msg_client_hello",
1080
                                                     "tls_modify_extensions_client_hello",
1081
                                                     "tls_current_timestamp",
1082
                                                     "tls_generate_ephemeral_key",
1083
                                                  });
1084

1085
                  result.test_eq("TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1086
               })
1✔
1087

1088
            // TODO: The rest of this test vector requires 0-RTT which is not
1089
            //       yet implemented. For now we can only test the client's
1090
            //       ability to offer a session resumption via PSK.
1091
         };
2✔
1092
      }
1✔
1093

1094
      std::vector<Test::Result> hello_retry_request(const VarMap& vars) override {
1✔
1095
         auto add_extensions_and_sort = [flights = 0](Botan::TLS::Extensions& exts,
3✔
1096
                                                      Botan::TLS::Connection_Side side,
1097
                                                      Botan::TLS::Handshake_Type which_message) mutable {
4✔
1098
            if(which_message == Handshake_Type::ClientHello) {
2✔
1099
               ++flights;
2✔
1100

1101
               if(flights == 1) {
2✔
1102
                  add_renegotiation_extension(exts);
1✔
1103
               }
1104

1105
               // For some reason RFC8448 decided to require this (fairly obscure) extension
1106
               // in the second flight of the Client_Hello.
1107
               if(flights == 2) {
2✔
1108
                  exts.add(new Padding(175));
1✔
1109
               }
1110

1111
               sort_client_extensions(exts, side);
2✔
1112
            }
1113
         };
2✔
1114

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

1119
         // 32 - client hello random
1120
         // 32 - eph. x25519 key pair
1121
         // 32 - eph. P-256 key pair
1122
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1123

1124
         std::unique_ptr<Client_Context> ctx;
1✔
1125

1126
         return {
1✔
1127
            Botan_Tests::CHECK(
1128
               "Client Hello",
1129
               [&](Test::Result& result) {
1✔
1130
                  ctx = std::make_unique<Client_Context>(std::move(rng),
3✔
1131
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_hrr_client"),
1✔
1132
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
1133
                                                         add_extensions_and_sort);
2✔
1134
                  result.confirm("client not closed", !ctx->client.is_closed());
2✔
1135

1136
                  ctx->check_callback_invocations(result,
7✔
1137
                                                  "client hello prepared",
1138
                                                  {
1139
                                                     "tls_emit_data",
1140
                                                     "tls_inspect_handshake_msg_client_hello",
1141
                                                     "tls_modify_extensions_client_hello",
1142
                                                     "tls_generate_ephemeral_key",
1143
                                                     "tls_current_timestamp",
1144
                                                  });
1145

1146
                  result.test_eq(
3✔
1147
                     "TLS client hello (1)", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
3✔
1148
               }),
1✔
1149

1150
            Botan_Tests::CHECK("Hello Retry Request .. second Client Hello",
1151
                               [&](Test::Result& result) {
1✔
1152
                                  result.require("ctx is available", ctx != nullptr);
2✔
1153
                                  ctx->client.received_data(vars.get_req_bin("Record_HelloRetryRequest"));
2✔
1154

1155
                                  ctx->check_callback_invocations(result,
8✔
1156
                                                                  "hello retry request received",
1157
                                                                  {
1158
                                                                     "tls_emit_data",
1159
                                                                     "tls_inspect_handshake_msg_hello_retry_request",
1160
                                                                     "tls_examine_extensions_hello_retry_request",
1161
                                                                     "tls_inspect_handshake_msg_client_hello",
1162
                                                                     "tls_modify_extensions_client_hello",
1163
                                                                     "tls_generate_ephemeral_key",
1164
                                                                  });
1165

1166
                                  result.test_eq("TLS client hello (2)",
3✔
1167
                                                 ctx->pull_send_buffer(),
2✔
1168
                                                 vars.get_req_bin("Record_ClientHello_2"));
2✔
1169
                               }),
1✔
1170

1171
            Botan_Tests::CHECK("Server Hello",
1172
                               [&](Test::Result& result) {
1✔
1173
                                  result.require("ctx is available", ctx != nullptr);
1✔
1174
                                  ctx->client.received_data(vars.get_req_bin("Record_ServerHello"));
2✔
1175

1176
                                  ctx->check_callback_invocations(result,
5✔
1177
                                                                  "server hello received",
1178
                                                                  {
1179
                                                                     "tls_inspect_handshake_msg_server_hello",
1180
                                                                     "tls_examine_extensions_server_hello",
1181
                                                                     "tls_ephemeral_key_agreement",
1182
                                                                  });
1183
                               }),
1✔
1184

1185
            Botan_Tests::CHECK(
1186
               "Server HS Messages .. Client Finished",
1187
               [&](Test::Result& result) {
1✔
1188
                  result.require("ctx is available", ctx != nullptr);
2✔
1189
                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
1190

1191
                  ctx->check_callback_invocations(result,
14✔
1192
                                                  "encrypted handshake messages received",
1193
                                                  {"tls_inspect_handshake_msg_encrypted_extensions",
1194
                                                   "tls_inspect_handshake_msg_certificate",
1195
                                                   "tls_inspect_handshake_msg_certificate_verify",
1196
                                                   "tls_inspect_handshake_msg_finished",
1197
                                                   "tls_examine_extensions_encrypted_extensions",
1198
                                                   "tls_examine_extensions_certificate",
1199
                                                   "tls_emit_data",
1200
                                                   "tls_current_timestamp",
1201
                                                   "tls_session_established",
1202
                                                   "tls_session_activated",
1203
                                                   "tls_verify_cert_chain",
1204
                                                   "tls_verify_message"});
1205

1206
                  result.test_eq("client finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
4✔
1207
               }),
1✔
1208

1209
            Botan_Tests::CHECK(
1210
               "Close Connection",
1211
               [&](Test::Result& result) {
1✔
1212
                  result.require("ctx is available", ctx != nullptr);
2✔
1213
                  ctx->client.close();
1✔
1214
                  ctx->check_callback_invocations(result, "encrypted handshake messages received", {"tls_emit_data"});
3✔
1215
                  result.test_eq(
2✔
1216
                     "client close notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1217

1218
                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1219
                  ctx->check_callback_invocations(
4✔
1220
                     result, "encrypted handshake messages received", {"tls_alert", "tls_peer_closed_connection"});
1221

1222
                  result.confirm("connection is closed", ctx->client.is_closed());
2✔
1223
               }),
1✔
1224
         };
6✔
1225
      }
1✔
1226

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

1230
         // 32 - for client hello random
1231
         // 32 - for eph. x25519 key pair
1232
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1233

1234
         auto add_extensions_and_sort = [&](Botan::TLS::Extensions& exts,
3✔
1235
                                            Botan::TLS::Connection_Side side,
1236
                                            Botan::TLS::Handshake_Type which_message) {
1237
            if(which_message == Handshake_Type::ClientHello) {
2✔
1238
               add_renegotiation_extension(exts);
1✔
1239
               sort_client_extensions(exts, side);
1✔
1240
            }
1241
         };
1242

1243
         std::unique_ptr<Client_Context> ctx;
1✔
1244

1245
         return {
1✔
1246
            Botan_Tests::CHECK(
1247
               "Client Hello",
1248
               [&](Test::Result& result) {
1✔
1249
                  ctx = std::make_unique<Client_Context>(std::move(rng),
3✔
1250
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
1251
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
1252
                                                         add_extensions_and_sort,
1✔
1253
                                                         std::nullopt,
1254
                                                         make_mock_signatures(vars));
3✔
1255

1256
                  ctx->check_callback_invocations(result,
7✔
1257
                                                  "initial callbacks",
1258
                                                  {
1259
                                                     "tls_emit_data",
1260
                                                     "tls_inspect_handshake_msg_client_hello",
1261
                                                     "tls_modify_extensions_client_hello",
1262
                                                     "tls_generate_ephemeral_key",
1263
                                                     "tls_current_timestamp",
1264
                                                  });
1265

1266
                  result.test_eq("Client Hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1267
               }),
1✔
1268

1269
            Botan_Tests::CHECK("Server Hello",
1270
                               [&](auto& result) {
1✔
1271
                                  ctx->client.received_data(vars.get_req_bin("Record_ServerHello"));
3✔
1272

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

1282
            Botan_Tests::CHECK("other handshake messages and client auth",
1283
                               [&](Test::Result& result) {
1✔
1284
                                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
3✔
1285

1286
                                  ctx->check_callback_invocations(result,
18✔
1287
                                                                  "signing callbacks invoked",
1288
                                                                  {
1289
                                                                     "tls_sign_message",
1290
                                                                     "tls_emit_data",
1291
                                                                     "tls_examine_extensions_encrypted_extensions",
1292
                                                                     "tls_examine_extensions_certificate",
1293
                                                                     "tls_examine_extensions_certificate_request",
1294
                                                                     "tls_modify_extensions_certificate",
1295
                                                                     "tls_inspect_handshake_msg_certificate",
1296
                                                                     "tls_inspect_handshake_msg_certificate_request",
1297
                                                                     "tls_inspect_handshake_msg_certificate_verify",
1298
                                                                     "tls_inspect_handshake_msg_encrypted_extensions",
1299
                                                                     "tls_inspect_handshake_msg_finished",
1300
                                                                     "tls_current_timestamp",
1301
                                                                     "tls_session_established",
1302
                                                                     "tls_session_activated",
1303
                                                                     "tls_verify_cert_chain",
1304
                                                                     "tls_verify_message",
1305
                                                                  });
1306

1307
                                  // ClientFinished contains the entire coalesced client authentication flight
1308
                                  // Messages: Certificate, CertificateVerify, Finished
1309
                                  result.test_eq("Client Auth and Finished",
3✔
1310
                                                 ctx->pull_send_buffer(),
2✔
1311
                                                 vars.get_req_bin("Record_ClientFinished"));
2✔
1312
                               }),
1✔
1313

1314
            Botan_Tests::CHECK(
1315
               "Close Connection",
1316
               [&](Test::Result& result) {
1✔
1317
                  ctx->client.close();
2✔
1318
                  result.test_eq(
2✔
1319
                     "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
4✔
1320

1321
                  ctx->check_callback_invocations(result,
3✔
1322
                                                  "after sending close notify",
1323
                                                  {
1324
                                                     "tls_emit_data",
1325
                                                  });
1326

1327
                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1328
                  result.confirm("connection closed", ctx->client.is_closed());
2✔
1329

1330
                  ctx->check_callback_invocations(
4✔
1331
                     result, "after receiving close notify", {"tls_alert", "tls_peer_closed_connection"});
1332
               }),
1✔
1333
         };
5✔
1334
      }
1✔
1335

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

1339
         // 32 - client hello random
1340
         // 32 - legacy session ID
1341
         // 32 - eph. x25519 key pair
1342
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1343

1344
         auto add_extensions_and_sort = [&](Botan::TLS::Extensions& exts,
2✔
1345
                                            Botan::TLS::Connection_Side side,
1346
                                            Botan::TLS::Handshake_Type which_message) {
1347
            if(which_message == Handshake_Type::ClientHello) {
1✔
1348
               add_renegotiation_extension(exts);
1✔
1349
               sort_client_extensions(exts, side);
1✔
1350
            }
1351
         };
1352

1353
         std::unique_ptr<Client_Context> ctx;
1✔
1354

1355
         return {
1✔
1356
            Botan_Tests::CHECK(
1357
               "Client Hello",
1358
               [&](Test::Result& result) {
1✔
1359
                  ctx = std::make_unique<Client_Context>(std::move(rng),
3✔
1360
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_compat_client"),
1✔
1361
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
1362
                                                         add_extensions_and_sort);
2✔
1363

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

1366
                  ctx->check_callback_invocations(result,
7✔
1367
                                                  "client hello prepared",
1368
                                                  {
1369
                                                     "tls_emit_data",
1370
                                                     "tls_inspect_handshake_msg_client_hello",
1371
                                                     "tls_modify_extensions_client_hello",
1372
                                                     "tls_generate_ephemeral_key",
1373
                                                     "tls_current_timestamp",
1374
                                                  });
1375
               }),
1✔
1376

1377
            Botan_Tests::CHECK("Server Hello + other handshake messages",
1378
                               [&](Test::Result& result) {
1✔
1379
                                  result.require("ctx is available", ctx != nullptr);
2✔
1380
                                  ctx->client.received_data(Botan::concat(
3✔
1381
                                     vars.get_req_bin("Record_ServerHello"),
4✔
1382
                                     // ServerHandshakeMessages contains the expected ChangeCipherSpec record
1383
                                     vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1384

1385
                                  ctx->check_callback_invocations(result,
17✔
1386
                                                                  "callbacks after server's first flight",
1387
                                                                  {
1388
                                                                     "tls_inspect_handshake_msg_server_hello",
1389
                                                                     "tls_inspect_handshake_msg_encrypted_extensions",
1390
                                                                     "tls_inspect_handshake_msg_certificate",
1391
                                                                     "tls_inspect_handshake_msg_certificate_verify",
1392
                                                                     "tls_inspect_handshake_msg_finished",
1393
                                                                     "tls_examine_extensions_server_hello",
1394
                                                                     "tls_examine_extensions_encrypted_extensions",
1395
                                                                     "tls_examine_extensions_certificate",
1396
                                                                     "tls_emit_data",
1397
                                                                     "tls_current_timestamp",
1398
                                                                     "tls_session_established",
1399
                                                                     "tls_session_activated",
1400
                                                                     "tls_verify_cert_chain",
1401
                                                                     "tls_verify_message",
1402
                                                                     "tls_ephemeral_key_agreement",
1403
                                                                  });
1404

1405
                                  result.test_eq("CCS + Client Finished",
3✔
1406
                                                 ctx->pull_send_buffer(),
2✔
1407
                                                 // ClientFinished contains the expected ChangeCipherSpec record
1408
                                                 vars.get_req_bin("Record_ClientFinished"));
2✔
1409

1410
                                  result.confirm("client is ready to send application traffic",
2✔
1411
                                                 ctx->client.is_active());
1✔
1412
                               }),
1✔
1413

1414
            Botan_Tests::CHECK(
1415
               "Close connection",
1416
               [&](Test::Result& result) {
1✔
1417
                  result.require("ctx is available", ctx != nullptr);
2✔
1418
                  ctx->client.close();
1✔
1419

1420
                  result.test_eq(
2✔
1421
                     "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
4✔
1422

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

1426
                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1427

1428
                  result.confirm("client connection was terminated", ctx->client.is_closed());
2✔
1429
               }),
1✔
1430
         };
4✔
1431
      }
1✔
1432
};
1433

1434
class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 {
1✔
1435
   private:
1436
      std::string side() const override { return "Server"; }
5✔
1437

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

1441
         // 32 - for server hello random
1442
         // 32 - for KeyShare (eph. x25519 key pair)  --  I guess?
1443
         //  4 - for ticket_age_add (in New Session Ticket)
1444
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1445

1446
         std::unique_ptr<Server_Context> ctx;
1✔
1447

1448
         return {
1✔
1449
            Botan_Tests::CHECK("Send Client Hello",
1450
                               [&](Test::Result& result) {
1✔
1451
                                  auto add_early_data_and_sort = [&](Botan::TLS::Extensions& exts,
5✔
1452
                                                                     Botan::TLS::Connection_Side side,
1453
                                                                     Botan::TLS::Handshake_Type type) {
1454
                                     if(type == Handshake_Type::NewSessionTicket) {
4✔
1455
                                        exts.add(new EarlyDataIndication(1024));
1✔
1456
                                     }
1457
                                     sort_server_extensions(exts, side, type);
4✔
1458
                                  };
4✔
1459

1460
                                  ctx = std::make_unique<Server_Context>(
2✔
1461
                                     std::move(rng),
1✔
1462
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
1463
                                     vars.get_req_u64("CurrentTimestamp"),
5✔
1464
                                     add_early_data_and_sort,
1465
                                     make_mock_signatures(vars),
1✔
1466
                                     false,
2✔
1467
                                     std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
1468
                                               Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1469
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
1470

1471
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1472

1473
                                  ctx->check_callback_invocations(result,
16✔
1474
                                                                  "client hello received",
1475
                                                                  {"tls_emit_data",
1476
                                                                   "tls_examine_extensions_client_hello",
1477
                                                                   "tls_modify_extensions_server_hello",
1478
                                                                   "tls_modify_extensions_encrypted_extensions",
1479
                                                                   "tls_modify_extensions_certificate",
1480
                                                                   "tls_sign_message",
1481
                                                                   "tls_generate_ephemeral_key",
1482
                                                                   "tls_ephemeral_key_agreement",
1483
                                                                   "tls_inspect_handshake_msg_client_hello",
1484
                                                                   "tls_inspect_handshake_msg_server_hello",
1485
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
1486
                                                                   "tls_inspect_handshake_msg_certificate",
1487
                                                                   "tls_inspect_handshake_msg_certificate_verify",
1488
                                                                   "tls_inspect_handshake_msg_finished"});
1489
                               }),
1✔
1490

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

1496
                                  result.test_eq("Server Hello",
2✔
1497
                                                 msgs.at("server_hello")[0],
2✔
1498
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
1499
                                  result.test_eq("Encrypted Extensions",
3✔
1500
                                                 msgs.at("encrypted_extensions")[0],
2✔
1501
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
1502
                                  result.test_eq("Certificate",
3✔
1503
                                                 msgs.at("certificate")[0],
2✔
1504
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
1505
                                  result.test_eq(
3✔
1506
                                     "CertificateVerify",
1507
                                     msgs.at("certificate_verify")[0],
2✔
1508
                                     strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
1509

1510
                                  result.test_eq("Server's entire first flight",
3✔
1511
                                                 ctx->pull_send_buffer(),
2✔
1512
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
1513
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1514

1515
                                  result.confirm("Server can now send application data", ctx->server.is_active());
3✔
1516
                               }),
1✔
1517

1518
            Botan_Tests::CHECK("Send Client Finished",
1519
                               [&](Test::Result& result) {
1✔
1520
                                  result.require("ctx is available", ctx != nullptr);
1✔
1521
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
1522

1523
                                  ctx->check_callback_invocations(result,
6✔
1524
                                                                  "client finished received",
1525
                                                                  {"tls_inspect_handshake_msg_finished",
1526
                                                                   "tls_current_timestamp",
1527
                                                                   "tls_session_established",
1528
                                                                   "tls_session_activated"});
1529
                               }),
1✔
1530

1531
            Botan_Tests::CHECK("Send Session Ticket",
1532
                               [&](Test::Result& result) {
1✔
1533
                                  result.require("ctx is available", ctx != nullptr);
1✔
1534
                                  const auto new_tickets = ctx->server.send_new_session_tickets(1);
1✔
1535

1536
                                  result.test_eq("session ticket was sent", new_tickets, 1);
1✔
1537

1538
                                  ctx->check_callback_invocations(result,
7✔
1539
                                                                  "issued new session ticket",
1540
                                                                  {"tls_inspect_handshake_msg_new_session_ticket",
1541
                                                                   "tls_current_timestamp",
1542
                                                                   "tls_emit_data",
1543
                                                                   "tls_modify_extensions_new_session_ticket",
1544
                                                                   "tls_should_persist_resumption_information"});
1545
                               }),
1✔
1546

1547
            Botan_Tests::CHECK("Verify generated new session ticket message",
1548
                               [&](Test::Result& result) {
1✔
1549
                                  result.require("ctx is available", ctx != nullptr);
2✔
1550
                                  result.test_eq("New Session Ticket",
2✔
1551
                                                 ctx->pull_send_buffer(),
2✔
1552
                                                 vars.get_req_bin("Record_NewSessionTicket"));
2✔
1553
                               }),
1✔
1554

1555
            Botan_Tests::CHECK(
1556
               "Receive Application Data",
1557
               [&](Test::Result& result) {
1✔
1558
                  result.require("ctx is available", ctx != nullptr);
1✔
1559
                  ctx->server.received_data(vars.get_req_bin("Record_Client_AppData"));
2✔
1560
                  ctx->check_callback_invocations(result, "application data received", {"tls_record_received"});
3✔
1561

1562
                  const auto rcvd = ctx->pull_receive_buffer();
1✔
1563
                  result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Client_AppData"));
3✔
1564
                  result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
2✔
1565
               }),
1✔
1566

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

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

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

1579
            Botan_Tests::CHECK("Receive Client's close_notify",
1580
                               [&](Test::Result& result) {
1✔
1581
                                  result.require("ctx is available", ctx != nullptr);
1✔
1582
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
1583

1584
                                  ctx->check_callback_invocations(
4✔
1585
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
1586

1587
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
1588
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
1589
                               }),
1✔
1590

1591
            Botan_Tests::CHECK("Expect Server close_notify",
1592
                               [&](Test::Result& result) {
1✔
1593
                                  result.require("ctx is available", ctx != nullptr);
2✔
1594
                                  ctx->server.close();
1✔
1595

1596
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
1597
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
1598
                                  result.test_eq("Server's close notify",
2✔
1599
                                                 ctx->pull_send_buffer(),
2✔
1600
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1601
                               }),
1✔
1602
         };
10✔
1603
      }
1✔
1604

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

1608
         // 32 - for server hello random
1609
         // 32 - for KeyShare (eph. x25519 key pair)
1610
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1611

1612
         std::unique_ptr<Server_Context> ctx;
1✔
1613

1614
         return {
1✔
1615
            Botan_Tests::CHECK("Receive Client Hello",
1616
                               [&](Test::Result& result) {
1✔
1617
                                  auto add_cookie_and_sort = [&](Botan::TLS::Extensions& exts,
3✔
1618
                                                                 Botan::TLS::Connection_Side side,
1619
                                                                 Botan::TLS::Handshake_Type type) {
1620
                                     if(type == Handshake_Type::EncryptedExtensions) {
2✔
1621
                                        exts.add(new EarlyDataIndication());
1✔
1622
                                     }
1623
                                     sort_server_extensions(exts, side, type);
2✔
1624
                                  };
2✔
1625

1626
                                  ctx = std::make_unique<Server_Context>(
2✔
1627
                                     std::move(rng),
1✔
1628
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
1629
                                     vars.get_req_u64("CurrentTimestamp"),
5✔
1630
                                     add_cookie_and_sort,
1631
                                     make_mock_signatures(vars),
1✔
1632
                                     false,
2✔
1633
                                     std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
1634
                                               Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1635
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
1636

1637
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1638

1639
                                  ctx->check_callback_invocations(result,
13✔
1640
                                                                  "client hello received",
1641
                                                                  {
1642
                                                                     "tls_emit_data",
1643
                                                                     "tls_current_timestamp",
1644
                                                                     "tls_generate_ephemeral_key",
1645
                                                                     "tls_ephemeral_key_agreement",
1646
                                                                     "tls_examine_extensions_client_hello",
1647
                                                                     "tls_modify_extensions_server_hello",
1648
                                                                     "tls_modify_extensions_encrypted_extensions",
1649
                                                                     "tls_inspect_handshake_msg_client_hello",
1650
                                                                     "tls_inspect_handshake_msg_server_hello",
1651
                                                                     "tls_inspect_handshake_msg_encrypted_extensions",
1652
                                                                     "tls_inspect_handshake_msg_finished",
1653
                                                                  });
1654
                               }),
1✔
1655

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

1661
                                  result.test_eq("Server Hello",
2✔
1662
                                                 msgs.at("server_hello")[0],
2✔
1663
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
1664
                                  result.test_eq("Encrypted Extensions",
3✔
1665
                                                 msgs.at("encrypted_extensions")[0],
2✔
1666
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
1667

1668
                                  result.test_eq("Server's entire first flight",
3✔
1669
                                                 ctx->pull_send_buffer(),
2✔
1670
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
1671
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1672

1673
                                  result.confirm("Server can now send application data", ctx->server.is_active());
3✔
1674
                               }),
1✔
1675

1676
            // TODO: The rest of this test vector requires 0-RTT which is not
1677
            //       yet implemented. For now we can only test the server's
1678
            //       ability to acknowledge a session resumption via PSK.
1679
         };
3✔
1680
      }
1✔
1681

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

1687
         // 32 - for server hello random
1688
         // 32 - for KeyShare (eph. P-256 key pair)
1689
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1690

1691
         std::unique_ptr<Server_Context> ctx;
1✔
1692

1693
         return {
1✔
1694
            Botan_Tests::CHECK("Receive Client Hello",
1695
                               [&](Test::Result& result) {
1✔
1696
                                  auto add_cookie_and_sort = [&](Botan::TLS::Extensions& exts,
5✔
1697
                                                                 Botan::TLS::Connection_Side side,
1698
                                                                 Botan::TLS::Handshake_Type type) {
1699
                                     if(type == Handshake_Type::HelloRetryRequest) {
4✔
1700
                                        // This cookie needs to be mocked into the HRR since RFC 8448 contains it.
1701
                                        exts.add(new Cookie(vars.get_opt_bin("HelloRetryRequest_Cookie")));
5✔
1702
                                     }
1703
                                     sort_server_extensions(exts, side, type);
4✔
1704
                                  };
4✔
1705

1706
                                  ctx = std::make_unique<Server_Context>(
2✔
1707
                                     std::move(rng),
1✔
1708
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_hrr_server"),
1✔
1709
                                     vars.get_req_u64("CurrentTimestamp"),
2✔
1710
                                     add_cookie_and_sort,
1711
                                     make_mock_signatures(vars));
3✔
1712
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
1713

1714
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1715

1716
                                  ctx->check_callback_invocations(result,
7✔
1717
                                                                  "client hello received",
1718
                                                                  {"tls_emit_data",
1719
                                                                   "tls_examine_extensions_client_hello",
1720
                                                                   "tls_modify_extensions_hello_retry_request",
1721
                                                                   "tls_inspect_handshake_msg_client_hello",
1722
                                                                   "tls_inspect_handshake_msg_hello_retry_request"});
1723
                               }),
1✔
1724

1725
            Botan_Tests::CHECK("Verify generated Hello Retry Request message",
1726
                               [&](Test::Result& result) {
1✔
1727
                                  result.require("ctx is available", ctx != nullptr);
2✔
1728
                                  result.test_eq("Server's Hello Retry Request record",
2✔
1729
                                                 ctx->pull_send_buffer(),
2✔
1730
                                                 vars.get_req_bin("Record_HelloRetryRequest"));
2✔
1731
                                  result.confirm("TLS handshake not yet finished", !ctx->server.is_active());
2✔
1732
                               }),
1✔
1733

1734
            Botan_Tests::CHECK("Receive updated Client Hello message",
1735
                               [&](Test::Result& result) {
1✔
1736
                                  result.require("ctx is available", ctx != nullptr);
1✔
1737
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_2"));
2✔
1738

1739
                                  ctx->check_callback_invocations(result,
16✔
1740
                                                                  "updated client hello received",
1741
                                                                  {"tls_emit_data",
1742
                                                                   "tls_examine_extensions_client_hello",
1743
                                                                   "tls_modify_extensions_server_hello",
1744
                                                                   "tls_modify_extensions_encrypted_extensions",
1745
                                                                   "tls_modify_extensions_certificate",
1746
                                                                   "tls_sign_message",
1747
                                                                   "tls_generate_ephemeral_key",
1748
                                                                   "tls_ephemeral_key_agreement",
1749
                                                                   "tls_inspect_handshake_msg_client_hello",
1750
                                                                   "tls_inspect_handshake_msg_server_hello",
1751
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
1752
                                                                   "tls_inspect_handshake_msg_certificate",
1753
                                                                   "tls_inspect_handshake_msg_certificate_verify",
1754
                                                                   "tls_inspect_handshake_msg_finished"});
1755
                               }),
1✔
1756

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

1762
                                  result.test_eq("Server Hello",
2✔
1763
                                                 msgs.at("server_hello")[0],
2✔
1764
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
1765
                                  result.test_eq("Encrypted Extensions",
3✔
1766
                                                 msgs.at("encrypted_extensions")[0],
2✔
1767
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
1768
                                  result.test_eq("Certificate",
3✔
1769
                                                 msgs.at("certificate")[0],
2✔
1770
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
1771
                                  result.test_eq(
3✔
1772
                                     "CertificateVerify",
1773
                                     msgs.at("certificate_verify")[0],
2✔
1774
                                     strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
1775
                                  result.test_eq("Finished",
3✔
1776
                                                 msgs.at("finished")[0],
2✔
1777
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
1778

1779
                                  result.test_eq("Server's entire second flight",
3✔
1780
                                                 ctx->pull_send_buffer(),
2✔
1781
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
1782
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1783
                                  result.confirm("Server could now send application data", ctx->server.is_active());
3✔
1784
                               }),
1✔
1785

1786
            Botan_Tests::CHECK("Receive Client Finished",
1787
                               [&](Test::Result& result) {
1✔
1788
                                  result.require("ctx is available", ctx != nullptr);
1✔
1789
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
1790

1791
                                  ctx->check_callback_invocations(result,
6✔
1792
                                                                  "client finished received",
1793
                                                                  {"tls_inspect_handshake_msg_finished",
1794
                                                                   "tls_current_timestamp",
1795
                                                                   "tls_session_established",
1796
                                                                   "tls_session_activated"});
1797

1798
                                  result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
1799
                               }),
1✔
1800

1801
            Botan_Tests::CHECK("Receive Client close_notify",
1802
                               [&](Test::Result& result) {
1✔
1803
                                  result.require("ctx is available", ctx != nullptr);
1✔
1804
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
1805

1806
                                  ctx->check_callback_invocations(
4✔
1807
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
1808

1809
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
1810
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
1811
                               }),
1✔
1812

1813
            Botan_Tests::CHECK("Expect Server close_notify",
1814
                               [&](Test::Result& result) {
1✔
1815
                                  result.require("ctx is available", ctx != nullptr);
2✔
1816
                                  ctx->server.close();
1✔
1817

1818
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
1819
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
1820
                                  result.test_eq("Server's close notify",
2✔
1821
                                                 ctx->pull_send_buffer(),
2✔
1822
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1823
                               }),
1✔
1824

1825
         };
8✔
1826
      }
1✔
1827

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

1831
         // 32 - for server hello random
1832
         // 32 - for KeyShare (eph. x25519 pair)
1833
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1834

1835
         std::unique_ptr<Server_Context> ctx;
1✔
1836

1837
         return {
1✔
1838
            Botan_Tests::CHECK("Receive Client Hello",
1839
                               [&](Test::Result& result) {
1✔
1840
                                  ctx = std::make_unique<Server_Context>(
2✔
1841
                                     std::move(rng),
1✔
1842
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_client_auth_server"),
1✔
1843
                                     vars.get_req_u64("CurrentTimestamp"),
3✔
1844
                                     sort_server_extensions,
1845
                                     make_mock_signatures(vars),
1✔
1846
                                     true /* use alternative certificate */);
2✔
1847
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
1848

1849
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1850

1851
                                  ctx->check_callback_invocations(result,
17✔
1852
                                                                  "client hello received",
1853
                                                                  {"tls_emit_data",
1854
                                                                   "tls_examine_extensions_client_hello",
1855
                                                                   "tls_modify_extensions_server_hello",
1856
                                                                   "tls_modify_extensions_encrypted_extensions",
1857
                                                                   "tls_modify_extensions_certificate",
1858
                                                                   "tls_sign_message",
1859
                                                                   "tls_generate_ephemeral_key",
1860
                                                                   "tls_ephemeral_key_agreement",
1861
                                                                   "tls_inspect_handshake_msg_client_hello",
1862
                                                                   "tls_inspect_handshake_msg_server_hello",
1863
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
1864
                                                                   "tls_inspect_handshake_msg_certificate_request",
1865
                                                                   "tls_inspect_handshake_msg_certificate",
1866
                                                                   "tls_inspect_handshake_msg_certificate_verify",
1867
                                                                   "tls_inspect_handshake_msg_finished"});
1868
                               }),
1✔
1869

1870
            Botan_Tests::CHECK(
1871
               "Verify server's generated handshake messages",
1872
               [&](Test::Result& result) {
1✔
1873
                  result.require("ctx is available", ctx != nullptr);
2✔
1874
                  const auto& msgs = ctx->observed_handshake_messages();
1✔
1875

1876
                  result.test_eq("Server Hello",
2✔
1877
                                 msgs.at("server_hello")[0],
2✔
1878
                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
1879
                  result.test_eq("Encrypted Extensions",
3✔
1880
                                 msgs.at("encrypted_extensions")[0],
2✔
1881
                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
1882
                  result.test_eq("Certificate Request",
3✔
1883
                                 msgs.at("certificate_request")[0],
2✔
1884
                                 strip_message_header(vars.get_opt_bin("Message_CertificateRequest")));
3✔
1885
                  result.test_eq("Certificate",
3✔
1886
                                 msgs.at("certificate")[0],
2✔
1887
                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
1888
                  result.test_eq("CertificateVerify",
3✔
1889
                                 msgs.at("certificate_verify")[0],
2✔
1890
                                 strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
1891
                  result.test_eq("Finished",
3✔
1892
                                 msgs.at("finished")[0],
2✔
1893
                                 strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
1894

1895
                  result.test_eq("Server's entire first flight",
3✔
1896
                                 ctx->pull_send_buffer(),
2✔
1897
                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
1898
                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1899

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

1904
            Botan_Tests::CHECK("Receive Client's second flight",
1905
                               [&](Test::Result& result) {
1✔
1906
                                  result.require("ctx is available", ctx != nullptr);
1✔
1907
                                  // This encrypted message contains the following messages:
1908
                                  // * client's Certificate message
1909
                                  // * client's Certificate_Verify message
1910
                                  // * client's Finished message
1911
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
1912

1913
                                  ctx->check_callback_invocations(result,
11✔
1914
                                                                  "client finished received",
1915
                                                                  {"tls_inspect_handshake_msg_certificate",
1916
                                                                   "tls_inspect_handshake_msg_certificate_verify",
1917
                                                                   "tls_inspect_handshake_msg_finished",
1918
                                                                   "tls_examine_extensions_certificate",
1919
                                                                   "tls_verify_cert_chain",
1920
                                                                   "tls_verify_message",
1921
                                                                   "tls_current_timestamp",
1922
                                                                   "tls_session_established",
1923
                                                                   "tls_session_activated"});
1924

1925
                                  const auto cert_chain = ctx->server.peer_cert_chain();
1✔
1926
                                  result.confirm("Received client's cert chain",
2✔
1927
                                                 !cert_chain.empty() && cert_chain.front() == client_certificate());
2✔
1928

1929
                                  result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
1930
                               }),
1✔
1931

1932
            Botan_Tests::CHECK("Receive Client close_notify",
1933
                               [&](Test::Result& result) {
1✔
1934
                                  result.require("ctx is available", ctx != nullptr);
1✔
1935
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
1936

1937
                                  ctx->check_callback_invocations(
4✔
1938
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
1939

1940
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
1941
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
1942
                               }),
1✔
1943

1944
            Botan_Tests::CHECK("Expect Server close_notify",
1945
                               [&](Test::Result& result) {
1✔
1946
                                  result.require("ctx is available", ctx != nullptr);
2✔
1947
                                  ctx->server.close();
1✔
1948

1949
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
1950
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
1951
                                  result.test_eq("Server's close notify",
2✔
1952
                                                 ctx->pull_send_buffer(),
2✔
1953
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1954
                               }),
1✔
1955

1956
         };
6✔
1957
      }
1✔
1958

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

1962
         // 32 - for server hello random
1963
         // 32 - for KeyShare (eph. x25519 pair)
1964
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1965

1966
         std::unique_ptr<Server_Context> ctx;
1✔
1967

1968
         return {
1✔
1969
            Botan_Tests::CHECK("Receive Client Hello",
1970
                               [&](Test::Result& result) {
1✔
1971
                                  ctx = std::make_unique<Server_Context>(
2✔
1972
                                     std::move(rng),
1✔
1973
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_compat_server"),
1✔
1974
                                     vars.get_req_u64("CurrentTimestamp"),
3✔
1975
                                     sort_server_extensions,
1976
                                     make_mock_signatures(vars));
3✔
1977
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
1978

1979
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1980

1981
                                  ctx->check_callback_invocations(result,
16✔
1982
                                                                  "client hello received",
1983
                                                                  {"tls_emit_data",
1984
                                                                   "tls_examine_extensions_client_hello",
1985
                                                                   "tls_modify_extensions_server_hello",
1986
                                                                   "tls_modify_extensions_encrypted_extensions",
1987
                                                                   "tls_modify_extensions_certificate",
1988
                                                                   "tls_sign_message",
1989
                                                                   "tls_generate_ephemeral_key",
1990
                                                                   "tls_ephemeral_key_agreement",
1991
                                                                   "tls_inspect_handshake_msg_client_hello",
1992
                                                                   "tls_inspect_handshake_msg_server_hello",
1993
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
1994
                                                                   "tls_inspect_handshake_msg_certificate",
1995
                                                                   "tls_inspect_handshake_msg_certificate_verify",
1996
                                                                   "tls_inspect_handshake_msg_finished"});
1997
                               }),
1✔
1998

1999
            Botan_Tests::CHECK("Verify server's generated handshake messages",
2000
                               [&](Test::Result& result) {
1✔
2001
                                  result.require("ctx is available", ctx != nullptr);
2✔
2002
                                  const auto& msgs = ctx->observed_handshake_messages();
1✔
2003

2004
                                  result.test_eq("Server Hello",
2✔
2005
                                                 msgs.at("server_hello")[0],
2✔
2006
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
2007
                                  result.test_eq("Encrypted Extensions",
3✔
2008
                                                 msgs.at("encrypted_extensions")[0],
2✔
2009
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2010
                                  result.test_eq("Certificate",
3✔
2011
                                                 msgs.at("certificate")[0],
2✔
2012
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
2013
                                  result.test_eq(
3✔
2014
                                     "CertificateVerify",
2015
                                     msgs.at("certificate_verify")[0],
2✔
2016
                                     strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
2017
                                  result.test_eq("Finished",
3✔
2018
                                                 msgs.at("finished")[0],
2✔
2019
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2020

2021
                                  // Those records contain the required Change Cipher Spec message the server must produce for compatibility mode compliance
2022
                                  result.test_eq("Server's entire first flight",
3✔
2023
                                                 ctx->pull_send_buffer(),
2✔
2024
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
2025
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2026

2027
                                  result.confirm("Server could now send application data", ctx->server.is_active());
3✔
2028
                               }),
1✔
2029

2030
            Botan_Tests::CHECK("Receive Client Finished",
2031
                               [&](Test::Result& result) {
1✔
2032
                                  result.require("ctx is available", ctx != nullptr);
1✔
2033
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2034

2035
                                  ctx->check_callback_invocations(result,
6✔
2036
                                                                  "client finished received",
2037
                                                                  {"tls_inspect_handshake_msg_finished",
2038
                                                                   "tls_current_timestamp",
2039
                                                                   "tls_session_established",
2040
                                                                   "tls_session_activated"});
2041

2042
                                  result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2043
                               }),
1✔
2044

2045
            Botan_Tests::CHECK("Receive Client close_notify",
2046
                               [&](Test::Result& result) {
1✔
2047
                                  result.require("ctx is available", ctx != nullptr);
1✔
2048
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2049

2050
                                  ctx->check_callback_invocations(
4✔
2051
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2052

2053
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2054
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
2055
                               }),
1✔
2056

2057
            Botan_Tests::CHECK("Expect Server close_notify",
2058
                               [&](Test::Result& result) {
1✔
2059
                                  result.require("ctx is available", ctx != nullptr);
2✔
2060
                                  ctx->server.close();
1✔
2061

2062
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2063
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2064
                                  result.test_eq("Server's close notify",
2✔
2065
                                                 ctx->pull_send_buffer(),
2✔
2066
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2067
                               }),
1✔
2068

2069
         };
6✔
2070
      }
1✔
2071
};
2072

2073
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_client", Test_TLS_RFC8448_Client);
2074
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_server", Test_TLS_RFC8448_Server);
2075

2076
#endif
2077

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