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

randombit / botan / 5356326050

23 Jun 2023 01:05PM UTC coverage: 91.728% (-0.008%) from 91.736%
5356326050

Pull #3595

github

web-flow
Merge a5b917599 into 92171c524
Pull Request #3595: Improve clang-tidy coverage

78163 of 85212 relevant lines covered (91.73%)

12690161.35 hits per line

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

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

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

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

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

25
   #include <botan/assert.h>
26
   #include <botan/credentials_manager.h>
27
   #include <botan/data_src.h>
28
   #include <botan/ecdsa.h>
29
   #include <botan/hash.h>
30
   #include <botan/pk_algs.h>
31
   #include <botan/pkcs8.h>
32
   #include <botan/rsa.h>
33
   #include <botan/tls.h>
34
   #include <botan/tls_extensions.h>
35
   #include <botan/tls_messages.h>
36
   #include <botan/internal/fmt.h>
37
   #include <botan/internal/stl_util.h>
38
#endif
39

40
namespace Botan_Tests {
41

42
#if defined(BOTAN_CAN_RUN_TEST_TLS_RFC8448)
43

44
namespace {
45

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

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

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

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

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

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

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

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

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

92
   private:
93
      size_t m_padding_bytes;
94
};
95

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

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

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

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

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

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

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

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

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

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

161
      void tls_session_established(const Botan::TLS::Session_Summary&) override {
8✔
162
         count_callback_invocation("tls_session_established");
8✔
163
      }
8✔
164

165
      void tls_session_activated() override {
8✔
166
         count_callback_invocation("tls_session_activated");
8✔
167
         session_activated_called = true;
8✔
168
      }
8✔
169

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

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

185
      std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const override {
×
186
         count_callback_invocation("tls_verify_cert_chain");
×
187
         return std::chrono::milliseconds(0);
×
188
      }
189

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

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

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

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

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

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

230
         throw Test_Error("TLS implementation produced an unexpected message to be signed: " + Botan::hex_encode(msg));
×
231
      }
232

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

242
      std::unique_ptr<PK_Key_Agreement_Key> tls_generate_ephemeral_key(
11✔
243
         const std::variant<TLS::Group_Params, DL_Group>& group, RandomNumberGenerator& rng) override {
244
         count_callback_invocation("tls_generate_ephemeral_key");
11✔
245
         return Callbacks::tls_generate_ephemeral_key(group, rng);
11✔
246
      }
247

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

257
      void tls_inspect_handshake_msg(const Handshake_Message& message) override {
72✔
258
         count_callback_invocation("tls_inspect_handshake_msg_" + message.type_string());
144✔
259

260
         try {
72✔
261
            auto serialized_message = message.serialize();
72✔
262

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

271
         return Callbacks::tls_inspect_handshake_msg(message);
72✔
272
      }
273

274
      std::string tls_server_choose_app_protocol(const std::vector<std::string>& client_protos) override {
×
275
         count_callback_invocation("tls_server_choose_app_protocol");
×
276
         return Callbacks::tls_server_choose_app_protocol(client_protos);
×
277
      }
278

279
      void tls_modify_extensions(Botan::TLS::Extensions& exts,
23✔
280
                                 Botan::TLS::Connection_Side side,
281
                                 Botan::TLS::Handshake_Type which_message) override {
282
         count_callback_invocation(std::string("tls_modify_extensions_") + handshake_type_to_string(which_message));
46✔
283
         m_modify_exts(exts, side, which_message);
23✔
284
         Callbacks::tls_modify_extensions(exts, side, which_message);
23✔
285
      }
23✔
286

287
      void tls_examine_extensions(const Botan::TLS::Extensions& extn,
22✔
288
                                  Connection_Side which_side,
289
                                  Botan::TLS::Handshake_Type which_message) override {
290
         count_callback_invocation(std::string("tls_examine_extensions_") + handshake_type_to_string(which_message));
44✔
291
         return Callbacks::tls_examine_extensions(extn, which_side, which_message);
22✔
292
      }
293

294
      std::string tls_peer_network_identity() override {
×
295
         count_callback_invocation("tls_peer_network_identity");
×
296
         return Callbacks::tls_peer_network_identity();
×
297
      }
298

299
      std::chrono::system_clock::time_point tls_current_timestamp() override {
17✔
300
         count_callback_invocation("tls_current_timestamp");
17✔
301
         return m_timestamp;
17✔
302
      }
303

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

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

308
      uint64_t last_received_seq_no() const { return received_seq_no; }
2✔
309

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

312
      void reset_callback_invocation_counters() { m_callback_invocations.clear(); }
40✔
313

314
   private:
315
      void count_callback_invocation(const std::string& callback_name) const {
238✔
316
         if(!m_callback_invocations.contains(callback_name)) {
238✔
317
            m_callback_invocations[callback_name] = 0;
225✔
318
         }
319

320
         m_callback_invocations[callback_name]++;
238✔
321
      }
238✔
322

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

329
   private:
330
      std::vector<uint8_t> send_buffer;
331
      std::vector<uint8_t> receive_buffer;
332
      uint64_t received_seq_no;
333
      Modify_Exts_Fn m_modify_exts;
334
      std::vector<MockSignature> m_mock_signatures;
335
      std::chrono::system_clock::time_point m_timestamp;
336

337
      mutable std::map<std::string, unsigned int> m_callback_invocations;
338
};
339

340
class Test_Credentials : public Botan::Credentials_Manager {
341
   public:
342
      explicit Test_Credentials(bool use_alternative_server_certificate) :
10✔
343
            m_alternative_server_certificate(use_alternative_server_certificate) {
10✔
344
         Botan::DataSource_Memory in(Test::read_data_file("tls_13_rfc8448/server_key.pem"));
20✔
345
         m_server_private_key.reset(Botan::PKCS8::load_key(in).release());
10✔
346

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

353
         m_client_private_key.reset(create_private_key("RSA", Test::rng(), "1024").release());
20✔
354
      }
10✔
355

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

366
      std::shared_ptr<Botan::Private_Key> private_key_for(const Botan::X509_Certificate& cert,
5✔
367
                                                          const std::string& type,
368
                                                          const std::string& context) override {
369
         BOTAN_UNUSED(cert, context);
5✔
370

371
         if(type == "tls-client") {
5✔
372
            return m_client_private_key;
1✔
373
         }
374

375
         if(m_alternative_server_certificate) {
4✔
376
            return m_bogus_alternative_server_private_key;
1✔
377
         }
378

379
         return m_server_private_key;
3✔
380
      }
381

382
   private:
383
      bool m_alternative_server_certificate;
384
      std::shared_ptr<Private_Key> m_client_private_key;
385
      std::shared_ptr<Private_Key> m_bogus_alternative_server_private_key;
386
      std::shared_ptr<Private_Key> m_server_private_key;
387
};
388

389
class RFC8448_Text_Policy : public Botan::TLS::Text_Policy {
10✔
390
   private:
391
      Botan::TLS::Text_Policy read_policy(const std::string& policy_file) {
10✔
392
         const std::string fspath = Test::data_file("tls-policy/" + policy_file + ".txt");
20✔
393

394
         std::ifstream is(fspath.c_str());
10✔
395
         if(!is.good()) {
10✔
396
            throw Test_Error("Missing policy file " + fspath);
×
397
         }
398

399
         return Botan::TLS::Text_Policy(is);
10✔
400
      }
20✔
401

402
   public:
403
      RFC8448_Text_Policy(const std::string& policy_file) : Botan::TLS::Text_Policy(read_policy(policy_file)) {}
10✔
404

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

429
      // Overriding the key exchange group selection to favour the server's key
430
      // exchange group preference. This is required to enforce a Hello Retry Request
431
      // when testing RFC 8448 5. from the server side.
432
      Named_Group choose_key_exchange_group(const std::vector<Group_Params>& supported_by_peer,
6✔
433
                                            const std::vector<Group_Params>& offered_by_peer) const override {
434
         BOTAN_UNUSED(offered_by_peer);
6✔
435

436
         const auto supported_by_us = key_exchange_groups();
6✔
437
         const auto selected_group =
6✔
438
            std::find_if(supported_by_us.begin(), supported_by_us.end(), [&](const auto group) {
6✔
439
               return value_exists(supported_by_peer, group);
12✔
440
            });
441

442
         return selected_group != supported_by_us.end() ? *selected_group : Named_Group::NONE;
6✔
443
      }
6✔
444
};
445

446
/**
447
 * In-Memory Session Manager that stores sessions verbatim, without encryption.
448
 * Therefor it is not dependent on a random number generator and can easily be
449
 * instrumented for test inspection.
450
 */
451
class RFC8448_Session_Manager : public Botan::TLS::Session_Manager {
452
   private:
453
      decltype(auto) find_by_handle(const Session_Handle& handle) {
2✔
454
         return [=](const Session_with_Handle& session) {
21✔
455
            if(session.handle.id().has_value() && handle.id().has_value() &&
4✔
456
               session.handle.id().value() == handle.id().value()) {
2✔
457
               return true;
458
            }
459
            if(session.handle.ticket().has_value() && handle.ticket().has_value() &&
8✔
460
               session.handle.ticket().value() == handle.ticket().value()) {
10✔
461
               return true;
2✔
462
            }
463
            return false;
464
         };
2✔
465
      }
466

467
   public:
468
      RFC8448_Session_Manager() : Session_Manager(Test::rng_as_shared()) {}
20✔
469

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

472
      void store(const Session& session, const Session_Handle& handle) override {
4✔
473
         m_sessions.push_back({session, handle});
4✔
474
      }
4✔
475

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

481
         if(m_sessions.size() != 1) {
1✔
482
            throw Botan_Tests::Test_Error("No mocked session handle available; Test bug?");
×
483
         }
484

485
         const auto& [mocked_session, handle] = m_sessions.front();
1✔
486
         if(mocked_session.master_secret() != session.master_secret()) {
1✔
487
            throw Botan_Tests::Test_Error("Generated session object does not match the expected mock");
×
488
         }
489

490
         return handle;
1✔
491
      }
492

493
      std::optional<Session> retrieve_one(const Session_Handle& handle) override {
1✔
494
         auto itr = std::find_if(m_sessions.begin(), m_sessions.end(), find_by_handle(handle));
1✔
495
         if(itr == m_sessions.end()) {
1✔
496
            return std::nullopt;
×
497
         } else {
498
            return itr->session;
2✔
499
         }
500
      }
501

502
      std::vector<Session_with_Handle> find_some(const Server_Information& info, const size_t) override {
5✔
503
         std::vector<Session_with_Handle> found_sessions;
5✔
504
         for(const auto& [session, handle] : m_sessions) {
6✔
505
            if(session.server_info() == info) {
1✔
506
               found_sessions.emplace_back(Session_with_Handle{session, handle});
2✔
507
            }
508
         }
509

510
         return found_sessions;
5✔
511
      }
×
512

513
      size_t remove(const Session_Handle& handle) override {
1✔
514
         // TODO: C++20 allows to simply implement the entire method like:
515
         //
516
         //   return std::erase_if(m_sessions, find_by_handle(handle));
517
         //
518
         // Unfortunately, at the time of this writing Android NDK shipped with
519
         // a std::erase_if that returns void.
520
         auto rm_itr = std::remove_if(m_sessions.begin(), m_sessions.end(), find_by_handle(handle));
1✔
521

522
         const auto elements_being_removed = std::distance(rm_itr, m_sessions.end());
1✔
523
         m_sessions.erase(rm_itr);
1✔
524
         return elements_being_removed;
1✔
525
      }
526

527
      size_t remove_all() override {
×
528
         const auto sessions = m_sessions.size();
×
529
         m_sessions.clear();
×
530
         return sessions;
×
531
      }
532

533
   private:
534
      std::vector<Session_with_Handle> m_sessions;
535
};
536

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

564
   public:
565
      virtual ~TLS_Context() = default;
50✔
566

567
      TLS_Context(TLS_Context&) = delete;
568
      TLS_Context& operator=(const TLS_Context&) = delete;
569

570
      TLS_Context(TLS_Context&&) = delete;
571
      TLS_Context& operator=(TLS_Context&&) = delete;
572

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

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

577
      uint64_t last_received_seq_no() const { return m_callbacks->last_received_seq_no(); }
2✔
578

579
      /**
580
       * Checks that all of the listed callbacks were called at least once, no other
581
       * callbacks were called in addition to the expected ones. After the checks are
582
       * done, the callback invocation counters are reset.
583
       */
584
      void check_callback_invocations(Test::Result& result,
40✔
585
                                      const std::string& context,
586
                                      const std::vector<std::string>& callback_names) {
587
         const auto& invokes = m_callbacks->callback_invocations();
40✔
588
         for(const auto& cbn : callback_names) {
258✔
589
            result.confirm(Botan::fmt("{} was invoked (Context: {})", cbn, context),
872✔
590
                           invokes.contains(cbn) && invokes.at(cbn) > 0);
218✔
591
         }
592

593
         for(const auto& invoke : invokes) {
258✔
594
            if(invoke.second == 0) {
218✔
595
               continue;
×
596
            }
597
            result.confirm(
436✔
598
               invoke.first + " was expected (Context: " + context + ")",
436✔
599
               std::find(callback_names.cbegin(), callback_names.cend(), invoke.first) != callback_names.cend());
436✔
600
         }
601

602
         m_callbacks->reset_callback_invocation_counters();
40✔
603
      }
40✔
604

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

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

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

611
      /**
612
       * Send application data through the secure channel
613
       */
614
      virtual void send(const std::vector<uint8_t>& data) = 0;
615

616
   protected:
617
      std::shared_ptr<Test_TLS_13_Callbacks> m_callbacks;  // NOLINT(*-non-private-member-variables-in-classes)
618
      std::shared_ptr<Test_Credentials> m_creds;           // NOLINT(*-non-private-member-variables-in-classes)
619

620
      std::shared_ptr<Botan::RandomNumberGenerator> m_rng;     // NOLINT(*-non-private-member-variables-in-classes)
621
      std::shared_ptr<RFC8448_Session_Manager> m_session_mgr;  // NOLINT(*-non-private-member-variables-in-classes)
622
      std::shared_ptr<const RFC8448_Text_Policy> m_policy;     // NOLINT(*-non-private-member-variables-in-classes)
623
};
624

625
class Client_Context : public TLS_Context {
626
   public:
627
      Client_Context(std::shared_ptr<Botan::RandomNumberGenerator> rng_in,
5✔
628
                     std::shared_ptr<const RFC8448_Text_Policy> policy,
629
                     uint64_t timestamp,
630
                     Modify_Exts_Fn modify_exts_cb,
631
                     std::optional<std::pair<Session, Session_Ticket>> session_and_ticket = std::nullopt,
632
                     std::vector<MockSignature> mock_signatures = {}) :
5✔
633
            TLS_Context(std::move(rng_in),
5✔
634
                        std::move(policy),
5✔
635
                        std::move(modify_exts_cb),
5✔
636
                        std::move(mock_signatures),
5✔
637
                        timestamp,
638
                        std::move(session_and_ticket),
5✔
639
                        false),
640
            client(m_callbacks,
20✔
641
                   m_session_mgr,
5✔
642
                   m_creds,
5✔
643
                   m_policy,
5✔
644
                   m_rng,
5✔
645
                   Botan::TLS::Server_Information("server"),
10✔
646
                   Botan::TLS::Protocol_Version::TLS_V13) {}
21✔
647

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

650
      Botan::TLS::Client client;  // NOLINT(*-non-private-member-variables-in-classes)
651
};
652

653
class Server_Context : public TLS_Context {
654
   public:
655
      Server_Context(std::shared_ptr<Botan::RandomNumberGenerator> rng,
5✔
656
                     std::shared_ptr<const RFC8448_Text_Policy> policy,
657
                     uint64_t timestamp,
658
                     Modify_Exts_Fn modify_exts_cb,
659
                     std::vector<MockSignature> mock_signatures,
660
                     bool use_alternative_server_certificate = false,
661
                     std::optional<std::pair<Session, Session_Ticket>> session_and_ticket = std::nullopt) :
5✔
662
            TLS_Context(std::move(rng),
5✔
663
                        std::move(policy),
5✔
664
                        std::move(modify_exts_cb),
5✔
665
                        std::move(mock_signatures),
5✔
666
                        timestamp,
667
                        std::move(session_and_ticket),
5✔
668
                        use_alternative_server_certificate),
669
            server(m_callbacks, m_session_mgr, m_creds, m_policy, m_rng, false /* DTLS NYI */) {}
37✔
670

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

673
      Botan::TLS::Server server;  // NOLINT(*-non-private-member-variables-in-classes)
674
};
675

676
/**
677
 * Because of the nature of the RFC 8448 test data we need to produce bit-compatible
678
 * TLS messages. Hence we sort the generated TLS extensions exactly as expected.
679
 */
680
void sort_client_extensions(Botan::TLS::Extensions& exts, Botan::TLS::Connection_Side side) {
6✔
681
   if(side == Botan::TLS::Connection_Side::Client) {
6✔
682
      const std::vector<Botan::TLS::Extension_Code> expected_order = {
6✔
683
         Botan::TLS::Extension_Code::ServerNameIndication,
684
         Botan::TLS::Extension_Code::SafeRenegotiation,
685
         Botan::TLS::Extension_Code::SupportedGroups,
686
         Botan::TLS::Extension_Code::SessionTicket,
687
         Botan::TLS::Extension_Code::KeyShare,
688
         Botan::TLS::Extension_Code::EarlyData,
689
         Botan::TLS::Extension_Code::SupportedVersions,
690
         Botan::TLS::Extension_Code::SignatureAlgorithms,
691
         Botan::TLS::Extension_Code::Cookie,
692
         Botan::TLS::Extension_Code::PskKeyExchangeModes,
693
         Botan::TLS::Extension_Code::RecordSizeLimit,
694
         Padding::static_type(),
695
         Botan::TLS::Extension_Code::PresharedKey,
696
      };
6✔
697

698
      for(const auto ext_type : expected_order) {
84✔
699
         auto ext = exts.take(ext_type);
78✔
700
         if(ext != nullptr) {
78✔
701
            exts.add(std::move(ext));
108✔
702
         }
703
      }
78✔
704
   }
6✔
705
}
6✔
706

707
/**
708
 * Because of the nature of the RFC 8448 test data we need to produce bit-compatible
709
 * TLS messages. Hence we sort the generated TLS extensions exactly as expected.
710
 */
711
void sort_server_extensions(Botan::TLS::Extensions& exts,
16✔
712
                            Botan::TLS::Connection_Side side,
713
                            Botan::TLS::Handshake_Type /*type*/) {
714
   if(side == Botan::TLS::Connection_Side::Server) {
16✔
715
      const std::vector<Botan::TLS::Extension_Code> expected_order = {
16✔
716
         Botan::TLS::Extension_Code::SupportedGroups,
717
         Botan::TLS::Extension_Code::KeyShare,
718
         Botan::TLS::Extension_Code::Cookie,
719
         Botan::TLS::Extension_Code::SupportedVersions,
720
         Botan::TLS::Extension_Code::SignatureAlgorithms,
721
         Botan::TLS::Extension_Code::RecordSizeLimit,
722
         Botan::TLS::Extension_Code::ServerNameIndication,
723
         Botan::TLS::Extension_Code::EarlyData,
724
      };
16✔
725

726
      for(const auto ext_type : expected_order) {
144✔
727
         auto ext = exts.take(ext_type);
128✔
728
         if(ext != nullptr) {
128✔
729
            exts.add(std::move(ext));
60✔
730
         }
731
      }
128✔
732
   }
16✔
733
}
16✔
734

735
void add_renegotiation_extension(Botan::TLS::Extensions& exts) {
5✔
736
   // Renegotiation is not possible in TLS 1.3. Nevertheless, RFC 8448 requires
737
   // to add this to the Client Hello for reasons.
738
   exts.add(new Renegotiation_Extension());
5✔
739
}
5✔
740

741
void add_early_data_indication(Botan::TLS::Extensions& exts) {
1✔
742
   exts.add(new Botan::TLS::EarlyDataIndication());
1✔
743
}
1✔
744

745
std::vector<uint8_t> strip_message_header(const std::vector<uint8_t>& msg) {
22✔
746
   BOTAN_ASSERT_NOMSG(msg.size() >= 4);
22✔
747
   return {msg.begin() + 4, msg.end()};
22✔
748
}
749

750
std::vector<MockSignature> make_mock_signatures(const VarMap& vars) {
6✔
751
   std::vector<MockSignature> result;
6✔
752

753
   auto mock = [&](const std::string& msg, const std::string& sig) {
18✔
754
      if(vars.has_key(msg) && vars.has_key(sig)) {
31✔
755
         result.push_back({vars.get_opt_bin(msg), vars.get_opt_bin(sig)});
7✔
756
      }
757
   };
12✔
758

759
   mock("Server_MessageToSign", "Server_MessageSignature");
12✔
760
   mock("Client_MessageToSign", "Client_MessageSignature");
12✔
761

762
   return result;
6✔
763
}
×
764

765
}  // namespace
766

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

805
      virtual std::string side() const = 0;
806

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

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

862
class Test_TLS_RFC8448_Client : public Test_TLS_RFC8448 {
1✔
863
   private:
864
      std::string side() const override { return "Client"; }
5✔
865

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

869
         // 32 - for client hello random
870
         // 32 - for KeyShare (eph. x25519 key pair)
871
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
872

873
         auto add_extensions_and_sort = [](Botan::TLS::Extensions& exts,
2✔
874
                                           Botan::TLS::Connection_Side side,
875
                                           Botan::TLS::Handshake_Type which_message) {
876
            if(which_message == Handshake_Type::ClientHello) {
1✔
877
               // For some reason, presumably checking compatibility, the RFC 8448 Client
878
               // Hello includes a (TLS 1.2) Session_Ticket extension. We don't normally add
879
               // this obsoleted extension in a TLS 1.3 client.
880
               exts.add(new Botan::TLS::Session_Ticket_Extension());
1✔
881

882
               add_renegotiation_extension(exts);
1✔
883
               sort_client_extensions(exts, side);
1✔
884
            }
885
         };
1✔
886

887
         std::unique_ptr<Client_Context> ctx;
1✔
888

889
         return {
1✔
890
            Botan_Tests::CHECK(
891
               "Client Hello",
892
               [&](Test::Result& result) {
1✔
893
                  ctx = std::make_unique<Client_Context>(rng,
3✔
894
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
895
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
896
                                                         add_extensions_and_sort);
2✔
897

898
                  result.confirm("client not closed", !ctx->client.is_closed());
2✔
899
                  ctx->check_callback_invocations(result,
7✔
900
                                                  "client hello prepared",
901
                                                  {
902
                                                     "tls_emit_data",
903
                                                     "tls_inspect_handshake_msg_client_hello",
904
                                                     "tls_modify_extensions_client_hello",
905
                                                     "tls_generate_ephemeral_key",
906
                                                     "tls_current_timestamp",
907
                                                  });
908

909
                  result.test_eq("TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
910
               }),
1✔
911

912
            Botan_Tests::CHECK(
913
               "Server Hello",
914
               [&](Test::Result& result) {
1✔
915
                  result.require("ctx is available", ctx != nullptr);
1✔
916
                  const auto server_hello = vars.get_req_bin("Record_ServerHello");
1✔
917
                  // splitting the input data to test partial reads
918
                  const std::vector<uint8_t> server_hello_a(server_hello.begin(), server_hello.begin() + 20);
1✔
919
                  const std::vector<uint8_t> server_hello_b(server_hello.begin() + 20, server_hello.end());
1✔
920

921
                  ctx->client.received_data(server_hello_a);
1✔
922
                  ctx->check_callback_invocations(result, "server hello partially received", {});
2✔
923

924
                  ctx->client.received_data(server_hello_b);
1✔
925
                  ctx->check_callback_invocations(result,
5✔
926
                                                  "server hello received",
927
                                                  {"tls_inspect_handshake_msg_server_hello",
928
                                                   "tls_examine_extensions_server_hello",
929
                                                   "tls_ephemeral_key_agreement"});
930

931
                  result.confirm("client is not yet active", !ctx->client.is_active());
3✔
932
               }),
3✔
933

934
            Botan_Tests::CHECK(
935
               "Server HS messages .. Client Finished",
936
               [&](Test::Result& result) {
1✔
937
                  result.require("ctx is available", ctx != nullptr);
3✔
938
                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
939

940
                  ctx->check_callback_invocations(result,
14✔
941
                                                  "encrypted handshake messages received",
942
                                                  {"tls_inspect_handshake_msg_encrypted_extensions",
943
                                                   "tls_inspect_handshake_msg_certificate",
944
                                                   "tls_inspect_handshake_msg_certificate_verify",
945
                                                   "tls_inspect_handshake_msg_finished",
946
                                                   "tls_examine_extensions_encrypted_extensions",
947
                                                   "tls_examine_extensions_certificate",
948
                                                   "tls_emit_data",
949
                                                   "tls_current_timestamp",
950
                                                   "tls_session_established",
951
                                                   "tls_session_activated",
952
                                                   "tls_verify_cert_chain",
953
                                                   "tls_verify_message"});
954
                  result.require("certificate exists", !ctx->certs_verified().empty());
1✔
955
                  result.require("correct certificate", ctx->certs_verified().front() == server_certificate());
2✔
956
                  result.require("client is active", ctx->client.is_active());
1✔
957

958
                  result.test_eq(
3✔
959
                     "correct handshake finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
3✔
960
               }),
1✔
961

962
            Botan_Tests::CHECK("Post-Handshake: NewSessionTicket",
963
                               [&](Test::Result& result) {
1✔
964
                                  result.require("ctx is available", ctx != nullptr);
1✔
965
                                  result.require("no sessions so far", ctx->stored_sessions().empty());
1✔
966
                                  ctx->client.received_data(vars.get_req_bin("Record_NewSessionTicket"));
2✔
967

968
                                  ctx->check_callback_invocations(result,
5✔
969
                                                                  "new session ticket received",
970
                                                                  {"tls_examine_extensions_new_session_ticket",
971
                                                                   "tls_should_persist_resumption_information",
972
                                                                   "tls_current_timestamp"});
973
                                  if(result.test_eq("session was stored", ctx->stored_sessions().size(), 1)) {
2✔
974
                                     const auto& [stored_session, stored_handle] = ctx->stored_sessions().front();
1✔
975
                                     result.require("session handle contains a ticket",
2✔
976
                                                    stored_handle.ticket().has_value());
1✔
977
                                     result.test_is_eq("session was serialized as expected",
3✔
978
                                                       Botan::unlock(stored_session.DER_encode()),
4✔
979
                                                       vars.get_req_bin("Client_SessionData"));
3✔
980
                                  }
981
                               }),
1✔
982

983
            Botan_Tests::CHECK("Send Application Data",
984
                               [&](Test::Result& result) {
1✔
985
                                  result.require("ctx is available", ctx != nullptr);
2✔
986
                                  ctx->send(vars.get_req_bin("Client_AppData"));
3✔
987

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

990
                                  result.test_eq("correct client application data",
3✔
991
                                                 ctx->pull_send_buffer(),
2✔
992
                                                 vars.get_req_bin("Record_Client_AppData"));
2✔
993
                               }),
1✔
994

995
            Botan_Tests::CHECK(
996
               "Receive Application Data",
997
               [&](Test::Result& result) {
1✔
998
                  result.require("ctx is available", ctx != nullptr);
1✔
999
                  ctx->client.received_data(vars.get_req_bin("Record_Server_AppData"));
2✔
1000

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

1003
                  const auto rcvd = ctx->pull_receive_buffer();
1✔
1004
                  result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Server_AppData"));
3✔
1005
                  result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(1));
2✔
1006
               }),
1✔
1007

1008
            Botan_Tests::CHECK("Close Connection",
1009
                               [&](Test::Result& result) {
1✔
1010
                                  result.require("ctx is available", ctx != nullptr);
2✔
1011
                                  ctx->client.close();
1✔
1012

1013
                                  result.test_eq("close payload",
2✔
1014
                                                 ctx->pull_send_buffer(),
2✔
1015
                                                 vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1016
                                  ctx->check_callback_invocations(result, "CLOSE_NOTIFY sent", {"tls_emit_data"});
3✔
1017

1018
                                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1019
                                  ctx->check_callback_invocations(
4✔
1020
                                     result, "CLOSE_NOTIFY received", {"tls_alert", "tls_peer_closed_connection"});
1021

1022
                                  result.confirm("connection is closed", ctx->client.is_closed());
2✔
1023
                               }),
1✔
1024
         };
8✔
1025
      }
2✔
1026

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

1030
         // 32 - for client hello random
1031
         // 32 - for KeyShare (eph. x25519 key pair)
1032
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1033

1034
         auto add_extensions_and_sort = [](Botan::TLS::Extensions& exts,
2✔
1035
                                           Botan::TLS::Connection_Side side,
1036
                                           Botan::TLS::Handshake_Type which_message) {
1037
            if(which_message == Handshake_Type::ClientHello) {
1✔
1038
               exts.add(new Padding(87));
1✔
1039

1040
               add_renegotiation_extension(exts);
1✔
1041

1042
               // TODO: Implement early data support and remove this 'hack'.
1043
               //
1044
               // Currently, the production implementation will never add this
1045
               // extension even if the resumed session would allow early data.
1046
               add_early_data_indication(exts);
1✔
1047
               sort_client_extensions(exts, side);
1✔
1048
            }
1049
         };
1✔
1050

1051
         std::unique_ptr<Client_Context> ctx;
1✔
1052

1053
         return {
1✔
1054
            Botan_Tests::CHECK(
1055
               "Client Hello",
1056
               [&](Test::Result& result) {
1✔
1057
                  ctx = std::make_unique<Client_Context>(
3✔
1058
                     std::move(rng),
1✔
1059
                     std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
1060
                     vars.get_req_u64("CurrentTimestamp"),
4✔
1061
                     add_extensions_and_sort,
1✔
1062
                     std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
1063
                               Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1064

1065
                  result.confirm("client not closed", !ctx->client.is_closed());
2✔
1066
                  ctx->check_callback_invocations(result,
7✔
1067
                                                  "client hello prepared",
1068
                                                  {
1069
                                                     "tls_emit_data",
1070
                                                     "tls_inspect_handshake_msg_client_hello",
1071
                                                     "tls_modify_extensions_client_hello",
1072
                                                     "tls_current_timestamp",
1073
                                                     "tls_generate_ephemeral_key",
1074
                                                  });
1075

1076
                  result.test_eq("TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1077
               })
1✔
1078

1079
            // TODO: The rest of this test vector requires 0-RTT which is not
1080
            //       yet implemented. For now we can only test the client's
1081
            //       ability to offer a session resumption via PSK.
1082
         };
2✔
1083
      }
1✔
1084

1085
      std::vector<Test::Result> hello_retry_request(const VarMap& vars) override {
1✔
1086
         auto add_extensions_and_sort = [flights = 0](Botan::TLS::Extensions& exts,
3✔
1087
                                                      Botan::TLS::Connection_Side side,
1088
                                                      Botan::TLS::Handshake_Type which_message) mutable {
4✔
1089
            if(which_message == Handshake_Type::ClientHello) {
2✔
1090
               ++flights;
2✔
1091

1092
               if(flights == 1) {
2✔
1093
                  add_renegotiation_extension(exts);
1✔
1094
               }
1095

1096
               // For some reason RFC8448 decided to require this (fairly obscure) extension
1097
               // in the second flight of the Client_Hello.
1098
               if(flights == 2) {
2✔
1099
                  exts.add(new Padding(175));
1✔
1100
               }
1101

1102
               sort_client_extensions(exts, side);
2✔
1103
            }
1104
         };
2✔
1105

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

1110
         // 32 - client hello random
1111
         // 32 - eph. x25519 key pair
1112
         // 32 - eph. P-256 key pair
1113
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1114

1115
         std::unique_ptr<Client_Context> ctx;
1✔
1116

1117
         return {
1✔
1118
            Botan_Tests::CHECK(
1119
               "Client Hello",
1120
               [&](Test::Result& result) {
1✔
1121
                  ctx = std::make_unique<Client_Context>(std::move(rng),
3✔
1122
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_hrr_client"),
1✔
1123
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
1124
                                                         add_extensions_and_sort);
2✔
1125
                  result.confirm("client not closed", !ctx->client.is_closed());
2✔
1126

1127
                  ctx->check_callback_invocations(result,
7✔
1128
                                                  "client hello prepared",
1129
                                                  {
1130
                                                     "tls_emit_data",
1131
                                                     "tls_inspect_handshake_msg_client_hello",
1132
                                                     "tls_modify_extensions_client_hello",
1133
                                                     "tls_generate_ephemeral_key",
1134
                                                     "tls_current_timestamp",
1135
                                                  });
1136

1137
                  result.test_eq(
3✔
1138
                     "TLS client hello (1)", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
3✔
1139
               }),
1✔
1140

1141
            Botan_Tests::CHECK("Hello Retry Request .. second Client Hello",
1142
                               [&](Test::Result& result) {
1✔
1143
                                  result.require("ctx is available", ctx != nullptr);
2✔
1144
                                  ctx->client.received_data(vars.get_req_bin("Record_HelloRetryRequest"));
2✔
1145

1146
                                  ctx->check_callback_invocations(result,
8✔
1147
                                                                  "hello retry request received",
1148
                                                                  {
1149
                                                                     "tls_emit_data",
1150
                                                                     "tls_inspect_handshake_msg_hello_retry_request",
1151
                                                                     "tls_examine_extensions_hello_retry_request",
1152
                                                                     "tls_inspect_handshake_msg_client_hello",
1153
                                                                     "tls_modify_extensions_client_hello",
1154
                                                                     "tls_generate_ephemeral_key",
1155
                                                                  });
1156

1157
                                  result.test_eq("TLS client hello (2)",
3✔
1158
                                                 ctx->pull_send_buffer(),
2✔
1159
                                                 vars.get_req_bin("Record_ClientHello_2"));
2✔
1160
                               }),
1✔
1161

1162
            Botan_Tests::CHECK("Server Hello",
1163
                               [&](Test::Result& result) {
1✔
1164
                                  result.require("ctx is available", ctx != nullptr);
1✔
1165
                                  ctx->client.received_data(vars.get_req_bin("Record_ServerHello"));
2✔
1166

1167
                                  ctx->check_callback_invocations(result,
5✔
1168
                                                                  "server hello received",
1169
                                                                  {
1170
                                                                     "tls_inspect_handshake_msg_server_hello",
1171
                                                                     "tls_examine_extensions_server_hello",
1172
                                                                     "tls_ephemeral_key_agreement",
1173
                                                                  });
1174
                               }),
1✔
1175

1176
            Botan_Tests::CHECK(
1177
               "Server HS Messages .. Client Finished",
1178
               [&](Test::Result& result) {
1✔
1179
                  result.require("ctx is available", ctx != nullptr);
2✔
1180
                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
1181

1182
                  ctx->check_callback_invocations(result,
14✔
1183
                                                  "encrypted handshake messages received",
1184
                                                  {"tls_inspect_handshake_msg_encrypted_extensions",
1185
                                                   "tls_inspect_handshake_msg_certificate",
1186
                                                   "tls_inspect_handshake_msg_certificate_verify",
1187
                                                   "tls_inspect_handshake_msg_finished",
1188
                                                   "tls_examine_extensions_encrypted_extensions",
1189
                                                   "tls_examine_extensions_certificate",
1190
                                                   "tls_emit_data",
1191
                                                   "tls_current_timestamp",
1192
                                                   "tls_session_established",
1193
                                                   "tls_session_activated",
1194
                                                   "tls_verify_cert_chain",
1195
                                                   "tls_verify_message"});
1196

1197
                  result.test_eq("client finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
4✔
1198
               }),
1✔
1199

1200
            Botan_Tests::CHECK(
1201
               "Close Connection",
1202
               [&](Test::Result& result) {
1✔
1203
                  result.require("ctx is available", ctx != nullptr);
2✔
1204
                  ctx->client.close();
1✔
1205
                  ctx->check_callback_invocations(result, "encrypted handshake messages received", {"tls_emit_data"});
3✔
1206
                  result.test_eq(
2✔
1207
                     "client close notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1208

1209
                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1210
                  ctx->check_callback_invocations(
4✔
1211
                     result, "encrypted handshake messages received", {"tls_alert", "tls_peer_closed_connection"});
1212

1213
                  result.confirm("connection is closed", ctx->client.is_closed());
2✔
1214
               }),
1✔
1215
         };
6✔
1216
      }
1✔
1217

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

1221
         // 32 - for client hello random
1222
         // 32 - for eph. x25519 key pair
1223
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1224

1225
         auto add_extensions_and_sort = [&](Botan::TLS::Extensions& exts,
3✔
1226
                                            Botan::TLS::Connection_Side side,
1227
                                            Botan::TLS::Handshake_Type which_message) {
1228
            if(which_message == Handshake_Type::ClientHello) {
2✔
1229
               add_renegotiation_extension(exts);
1✔
1230
               sort_client_extensions(exts, side);
1✔
1231
            }
1232
         };
1233

1234
         std::unique_ptr<Client_Context> ctx;
1✔
1235

1236
         return {
1✔
1237
            Botan_Tests::CHECK(
1238
               "Client Hello",
1239
               [&](Test::Result& result) {
1✔
1240
                  ctx = std::make_unique<Client_Context>(std::move(rng),
3✔
1241
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
1✔
1242
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
1243
                                                         add_extensions_and_sort,
1✔
1244
                                                         std::nullopt,
1245
                                                         make_mock_signatures(vars));
3✔
1246

1247
                  ctx->check_callback_invocations(result,
7✔
1248
                                                  "initial callbacks",
1249
                                                  {
1250
                                                     "tls_emit_data",
1251
                                                     "tls_inspect_handshake_msg_client_hello",
1252
                                                     "tls_modify_extensions_client_hello",
1253
                                                     "tls_generate_ephemeral_key",
1254
                                                     "tls_current_timestamp",
1255
                                                  });
1256

1257
                  result.test_eq("Client Hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1258
               }),
1✔
1259

1260
            Botan_Tests::CHECK("Server Hello",
1261
                               [&](auto& result) {
1✔
1262
                                  result.require("ctx is available", ctx != nullptr);
2✔
1263
                                  ctx->client.received_data(vars.get_req_bin("Record_ServerHello"));
3✔
1264

1265
                                  ctx->check_callback_invocations(result,
5✔
1266
                                                                  "callbacks after server hello",
1267
                                                                  {
1268
                                                                     "tls_examine_extensions_server_hello",
1269
                                                                     "tls_inspect_handshake_msg_server_hello",
1270
                                                                     "tls_ephemeral_key_agreement",
1271
                                                                  });
1272
                               }),
1✔
1273

1274
            Botan_Tests::CHECK("other handshake messages and client auth",
1275
                               [&](Test::Result& result) {
1✔
1276
                                  result.require("ctx is available", ctx != nullptr);
2✔
1277
                                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
1278

1279
                                  ctx->check_callback_invocations(result,
18✔
1280
                                                                  "signing callbacks invoked",
1281
                                                                  {
1282
                                                                     "tls_sign_message",
1283
                                                                     "tls_emit_data",
1284
                                                                     "tls_examine_extensions_encrypted_extensions",
1285
                                                                     "tls_examine_extensions_certificate",
1286
                                                                     "tls_examine_extensions_certificate_request",
1287
                                                                     "tls_modify_extensions_certificate",
1288
                                                                     "tls_inspect_handshake_msg_certificate",
1289
                                                                     "tls_inspect_handshake_msg_certificate_request",
1290
                                                                     "tls_inspect_handshake_msg_certificate_verify",
1291
                                                                     "tls_inspect_handshake_msg_encrypted_extensions",
1292
                                                                     "tls_inspect_handshake_msg_finished",
1293
                                                                     "tls_current_timestamp",
1294
                                                                     "tls_session_established",
1295
                                                                     "tls_session_activated",
1296
                                                                     "tls_verify_cert_chain",
1297
                                                                     "tls_verify_message",
1298
                                                                  });
1299

1300
                                  // ClientFinished contains the entire coalesced client authentication flight
1301
                                  // Messages: Certificate, CertificateVerify, Finished
1302
                                  result.test_eq("Client Auth and Finished",
3✔
1303
                                                 ctx->pull_send_buffer(),
2✔
1304
                                                 vars.get_req_bin("Record_ClientFinished"));
2✔
1305
                               }),
1✔
1306

1307
            Botan_Tests::CHECK(
1308
               "Close Connection",
1309
               [&](Test::Result& result) {
1✔
1310
                  result.require("ctx is available", ctx != nullptr);
2✔
1311
                  ctx->client.close();
1✔
1312
                  result.test_eq(
2✔
1313
                     "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
4✔
1314

1315
                  ctx->check_callback_invocations(result,
3✔
1316
                                                  "after sending close notify",
1317
                                                  {
1318
                                                     "tls_emit_data",
1319
                                                  });
1320

1321
                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1322
                  result.confirm("connection closed", ctx->client.is_closed());
2✔
1323

1324
                  ctx->check_callback_invocations(
4✔
1325
                     result, "after receiving close notify", {"tls_alert", "tls_peer_closed_connection"});
1326
               }),
1✔
1327
         };
5✔
1328
      }
1✔
1329

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

1333
         // 32 - client hello random
1334
         // 32 - legacy session ID
1335
         // 32 - eph. x25519 key pair
1336
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1337

1338
         auto add_extensions_and_sort = [&](Botan::TLS::Extensions& exts,
2✔
1339
                                            Botan::TLS::Connection_Side side,
1340
                                            Botan::TLS::Handshake_Type which_message) {
1341
            if(which_message == Handshake_Type::ClientHello) {
1✔
1342
               add_renegotiation_extension(exts);
1✔
1343
               sort_client_extensions(exts, side);
1✔
1344
            }
1345
         };
1346

1347
         std::unique_ptr<Client_Context> ctx;
1✔
1348

1349
         return {
1✔
1350
            Botan_Tests::CHECK(
1351
               "Client Hello",
1352
               [&](Test::Result& result) {
1✔
1353
                  ctx = std::make_unique<Client_Context>(std::move(rng),
3✔
1354
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_compat_client"),
1✔
1355
                                                         vars.get_req_u64("CurrentTimestamp"),
2✔
1356
                                                         add_extensions_and_sort);
2✔
1357

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

1360
                  ctx->check_callback_invocations(result,
7✔
1361
                                                  "client hello prepared",
1362
                                                  {
1363
                                                     "tls_emit_data",
1364
                                                     "tls_inspect_handshake_msg_client_hello",
1365
                                                     "tls_modify_extensions_client_hello",
1366
                                                     "tls_generate_ephemeral_key",
1367
                                                     "tls_current_timestamp",
1368
                                                  });
1369
               }),
1✔
1370

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

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

1399
                                  result.test_eq("CCS + Client Finished",
3✔
1400
                                                 ctx->pull_send_buffer(),
2✔
1401
                                                 // ClientFinished contains the expected ChangeCipherSpec record
1402
                                                 vars.get_req_bin("Record_ClientFinished"));
2✔
1403

1404
                                  result.confirm("client is ready to send application traffic",
2✔
1405
                                                 ctx->client.is_active());
1✔
1406
                               }),
1✔
1407

1408
            Botan_Tests::CHECK(
1409
               "Close connection",
1410
               [&](Test::Result& result) {
1✔
1411
                  result.require("ctx is available", ctx != nullptr);
2✔
1412
                  ctx->client.close();
1✔
1413

1414
                  result.test_eq(
2✔
1415
                     "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
4✔
1416

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

1420
                  ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1421

1422
                  result.confirm("client connection was terminated", ctx->client.is_closed());
2✔
1423
               }),
1✔
1424
         };
4✔
1425
      }
1✔
1426
};
1427

1428
class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 {
1✔
1429
   private:
1430
      std::string side() const override { return "Server"; }
5✔
1431

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

1435
         // 32 - for server hello random
1436
         // 32 - for KeyShare (eph. x25519 key pair)  --  I guess?
1437
         //  4 - for ticket_age_add (in New Session Ticket)
1438
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1439

1440
         std::unique_ptr<Server_Context> ctx;
1✔
1441

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

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

1465
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1466

1467
                                  ctx->check_callback_invocations(result,
16✔
1468
                                                                  "client hello received",
1469
                                                                  {"tls_emit_data",
1470
                                                                   "tls_examine_extensions_client_hello",
1471
                                                                   "tls_modify_extensions_server_hello",
1472
                                                                   "tls_modify_extensions_encrypted_extensions",
1473
                                                                   "tls_modify_extensions_certificate",
1474
                                                                   "tls_sign_message",
1475
                                                                   "tls_generate_ephemeral_key",
1476
                                                                   "tls_ephemeral_key_agreement",
1477
                                                                   "tls_inspect_handshake_msg_client_hello",
1478
                                                                   "tls_inspect_handshake_msg_server_hello",
1479
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
1480
                                                                   "tls_inspect_handshake_msg_certificate",
1481
                                                                   "tls_inspect_handshake_msg_certificate_verify",
1482
                                                                   "tls_inspect_handshake_msg_finished"});
1483
                               }),
1✔
1484

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

1490
                                  result.test_eq("Server Hello",
2✔
1491
                                                 msgs.at("server_hello")[0],
2✔
1492
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
1493
                                  result.test_eq("Encrypted Extensions",
3✔
1494
                                                 msgs.at("encrypted_extensions")[0],
2✔
1495
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
1496
                                  result.test_eq("Certificate",
3✔
1497
                                                 msgs.at("certificate")[0],
2✔
1498
                                                 strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
1499
                                  result.test_eq(
3✔
1500
                                     "CertificateVerify",
1501
                                     msgs.at("certificate_verify")[0],
2✔
1502
                                     strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
1503

1504
                                  result.test_eq("Server's entire first flight",
3✔
1505
                                                 ctx->pull_send_buffer(),
2✔
1506
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
1507
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1508

1509
                                  result.confirm("Server can now send application data", ctx->server.is_active());
3✔
1510
                               }),
1✔
1511

1512
            Botan_Tests::CHECK("Send Client Finished",
1513
                               [&](Test::Result& result) {
1✔
1514
                                  result.require("ctx is available", ctx != nullptr);
1✔
1515
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
1516

1517
                                  ctx->check_callback_invocations(result,
6✔
1518
                                                                  "client finished received",
1519
                                                                  {"tls_inspect_handshake_msg_finished",
1520
                                                                   "tls_current_timestamp",
1521
                                                                   "tls_session_established",
1522
                                                                   "tls_session_activated"});
1523
                               }),
1✔
1524

1525
            Botan_Tests::CHECK("Send Session Ticket",
1526
                               [&](Test::Result& result) {
1✔
1527
                                  result.require("ctx is available", ctx != nullptr);
1✔
1528
                                  const auto new_tickets = ctx->server.send_new_session_tickets(1);
1✔
1529

1530
                                  result.test_eq("session ticket was sent", new_tickets, 1);
1✔
1531

1532
                                  ctx->check_callback_invocations(result,
7✔
1533
                                                                  "issued new session ticket",
1534
                                                                  {"tls_inspect_handshake_msg_new_session_ticket",
1535
                                                                   "tls_current_timestamp",
1536
                                                                   "tls_emit_data",
1537
                                                                   "tls_modify_extensions_new_session_ticket",
1538
                                                                   "tls_should_persist_resumption_information"});
1539
                               }),
1✔
1540

1541
            Botan_Tests::CHECK("Verify generated new session ticket message",
1542
                               [&](Test::Result& result) {
1✔
1543
                                  result.require("ctx is available", ctx != nullptr);
2✔
1544
                                  result.test_eq("New Session Ticket",
2✔
1545
                                                 ctx->pull_send_buffer(),
2✔
1546
                                                 vars.get_req_bin("Record_NewSessionTicket"));
2✔
1547
                               }),
1✔
1548

1549
            Botan_Tests::CHECK(
1550
               "Receive Application Data",
1551
               [&](Test::Result& result) {
1✔
1552
                  result.require("ctx is available", ctx != nullptr);
1✔
1553
                  ctx->server.received_data(vars.get_req_bin("Record_Client_AppData"));
2✔
1554
                  ctx->check_callback_invocations(result, "application data received", {"tls_record_received"});
3✔
1555

1556
                  const auto rcvd = ctx->pull_receive_buffer();
1✔
1557
                  result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Client_AppData"));
3✔
1558
                  result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
2✔
1559
               }),
1✔
1560

1561
            Botan_Tests::CHECK("Send Application Data",
1562
                               [&](Test::Result& result) {
1✔
1563
                                  result.require("ctx is available", ctx != nullptr);
2✔
1564
                                  ctx->send(vars.get_req_bin("Server_AppData"));
3✔
1565

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

1568
                                  result.test_eq("correct server application data",
3✔
1569
                                                 ctx->pull_send_buffer(),
2✔
1570
                                                 vars.get_req_bin("Record_Server_AppData"));
2✔
1571
                               }),
1✔
1572

1573
            Botan_Tests::CHECK("Receive Client's close_notify",
1574
                               [&](Test::Result& result) {
1✔
1575
                                  result.require("ctx is available", ctx != nullptr);
1✔
1576
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
1577

1578
                                  ctx->check_callback_invocations(
4✔
1579
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
1580

1581
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
1582
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
1583
                               }),
1✔
1584

1585
            Botan_Tests::CHECK("Expect Server close_notify",
1586
                               [&](Test::Result& result) {
1✔
1587
                                  result.require("ctx is available", ctx != nullptr);
2✔
1588
                                  ctx->server.close();
1✔
1589

1590
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
1591
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
1592
                                  result.test_eq("Server's close notify",
2✔
1593
                                                 ctx->pull_send_buffer(),
2✔
1594
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1595
                               }),
1✔
1596
         };
10✔
1597
      }
1✔
1598

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

1602
         // 32 - for server hello random
1603
         // 32 - for KeyShare (eph. x25519 key pair)
1604
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1605

1606
         std::unique_ptr<Server_Context> ctx;
1✔
1607

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

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

1631
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1632

1633
                                  ctx->check_callback_invocations(result,
13✔
1634
                                                                  "client hello received",
1635
                                                                  {
1636
                                                                     "tls_emit_data",
1637
                                                                     "tls_current_timestamp",
1638
                                                                     "tls_generate_ephemeral_key",
1639
                                                                     "tls_ephemeral_key_agreement",
1640
                                                                     "tls_examine_extensions_client_hello",
1641
                                                                     "tls_modify_extensions_server_hello",
1642
                                                                     "tls_modify_extensions_encrypted_extensions",
1643
                                                                     "tls_inspect_handshake_msg_client_hello",
1644
                                                                     "tls_inspect_handshake_msg_server_hello",
1645
                                                                     "tls_inspect_handshake_msg_encrypted_extensions",
1646
                                                                     "tls_inspect_handshake_msg_finished",
1647
                                                                  });
1648
                               }),
1✔
1649

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

1655
                                  result.test_eq("Server Hello",
2✔
1656
                                                 msgs.at("server_hello")[0],
2✔
1657
                                                 strip_message_header(vars.get_opt_bin("Message_ServerHello")));
4✔
1658
                                  result.test_eq("Encrypted Extensions",
3✔
1659
                                                 msgs.at("encrypted_extensions")[0],
2✔
1660
                                                 strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
1661

1662
                                  result.test_eq("Server's entire first flight",
3✔
1663
                                                 ctx->pull_send_buffer(),
2✔
1664
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
1665
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1666

1667
                                  result.confirm("Server can now send application data", ctx->server.is_active());
3✔
1668
                               }),
1✔
1669

1670
            // TODO: The rest of this test vector requires 0-RTT which is not
1671
            //       yet implemented. For now we can only test the server's
1672
            //       ability to acknowledge a session resumption via PSK.
1673
         };
3✔
1674
      }
1✔
1675

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

1681
         // 32 - for server hello random
1682
         // 32 - for KeyShare (eph. P-256 key pair)
1683
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1684

1685
         std::unique_ptr<Server_Context> ctx;
1✔
1686

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

1700
                                  ctx = std::make_unique<Server_Context>(
2✔
1701
                                     std::move(rng),
1✔
1702
                                     std::make_shared<RFC8448_Text_Policy>("rfc8448_hrr_server"),
1✔
1703
                                     vars.get_req_u64("CurrentTimestamp"),
2✔
1704
                                     add_cookie_and_sort,
1705
                                     make_mock_signatures(vars));
3✔
1706
                                  result.confirm("server not closed", !ctx->server.is_closed());
2✔
1707

1708
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1709

1710
                                  ctx->check_callback_invocations(result,
7✔
1711
                                                                  "client hello received",
1712
                                                                  {"tls_emit_data",
1713
                                                                   "tls_examine_extensions_client_hello",
1714
                                                                   "tls_modify_extensions_hello_retry_request",
1715
                                                                   "tls_inspect_handshake_msg_client_hello",
1716
                                                                   "tls_inspect_handshake_msg_hello_retry_request"});
1717
                               }),
1✔
1718

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

1728
            Botan_Tests::CHECK("Receive updated Client Hello message",
1729
                               [&](Test::Result& result) {
1✔
1730
                                  result.require("ctx is available", ctx != nullptr);
1✔
1731
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_2"));
2✔
1732

1733
                                  ctx->check_callback_invocations(result,
16✔
1734
                                                                  "updated client hello received",
1735
                                                                  {"tls_emit_data",
1736
                                                                   "tls_examine_extensions_client_hello",
1737
                                                                   "tls_modify_extensions_server_hello",
1738
                                                                   "tls_modify_extensions_encrypted_extensions",
1739
                                                                   "tls_modify_extensions_certificate",
1740
                                                                   "tls_sign_message",
1741
                                                                   "tls_generate_ephemeral_key",
1742
                                                                   "tls_ephemeral_key_agreement",
1743
                                                                   "tls_inspect_handshake_msg_client_hello",
1744
                                                                   "tls_inspect_handshake_msg_server_hello",
1745
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
1746
                                                                   "tls_inspect_handshake_msg_certificate",
1747
                                                                   "tls_inspect_handshake_msg_certificate_verify",
1748
                                                                   "tls_inspect_handshake_msg_finished"});
1749
                               }),
1✔
1750

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

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

1773
                                  result.test_eq("Server's entire second flight",
3✔
1774
                                                 ctx->pull_send_buffer(),
2✔
1775
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
1776
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1777
                                  result.confirm("Server could now send application data", ctx->server.is_active());
3✔
1778
                               }),
1✔
1779

1780
            Botan_Tests::CHECK("Receive Client Finished",
1781
                               [&](Test::Result& result) {
1✔
1782
                                  result.require("ctx is available", ctx != nullptr);
1✔
1783
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
1784

1785
                                  ctx->check_callback_invocations(result,
6✔
1786
                                                                  "client finished received",
1787
                                                                  {"tls_inspect_handshake_msg_finished",
1788
                                                                   "tls_current_timestamp",
1789
                                                                   "tls_session_established",
1790
                                                                   "tls_session_activated"});
1791

1792
                                  result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
1793
                               }),
1✔
1794

1795
            Botan_Tests::CHECK("Receive Client close_notify",
1796
                               [&](Test::Result& result) {
1✔
1797
                                  result.require("ctx is available", ctx != nullptr);
1✔
1798
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
1799

1800
                                  ctx->check_callback_invocations(
4✔
1801
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
1802

1803
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
1804
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
1805
                               }),
1✔
1806

1807
            Botan_Tests::CHECK("Expect Server close_notify",
1808
                               [&](Test::Result& result) {
1✔
1809
                                  result.require("ctx is available", ctx != nullptr);
2✔
1810
                                  ctx->server.close();
1✔
1811

1812
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
1813
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
1814
                                  result.test_eq("Server's close notify",
2✔
1815
                                                 ctx->pull_send_buffer(),
2✔
1816
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1817
                               }),
1✔
1818

1819
         };
8✔
1820
      }
1✔
1821

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

1825
         // 32 - for server hello random
1826
         // 32 - for KeyShare (eph. x25519 pair)
1827
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1828

1829
         std::unique_ptr<Server_Context> ctx;
1✔
1830

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

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

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

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

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

1889
                  result.test_eq("Server's entire first flight",
3✔
1890
                                 ctx->pull_send_buffer(),
2✔
1891
                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
1892
                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1893

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

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

1907
                                  ctx->check_callback_invocations(result,
11✔
1908
                                                                  "client finished received",
1909
                                                                  {"tls_inspect_handshake_msg_certificate",
1910
                                                                   "tls_inspect_handshake_msg_certificate_verify",
1911
                                                                   "tls_inspect_handshake_msg_finished",
1912
                                                                   "tls_examine_extensions_certificate",
1913
                                                                   "tls_verify_cert_chain",
1914
                                                                   "tls_verify_message",
1915
                                                                   "tls_current_timestamp",
1916
                                                                   "tls_session_established",
1917
                                                                   "tls_session_activated"});
1918

1919
                                  const auto cert_chain = ctx->server.peer_cert_chain();
1✔
1920
                                  result.confirm("Received client's cert chain",
2✔
1921
                                                 !cert_chain.empty() && cert_chain.front() == client_certificate());
2✔
1922

1923
                                  result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
1924
                               }),
1✔
1925

1926
            Botan_Tests::CHECK("Receive Client close_notify",
1927
                               [&](Test::Result& result) {
1✔
1928
                                  result.require("ctx is available", ctx != nullptr);
1✔
1929
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
1930

1931
                                  ctx->check_callback_invocations(
4✔
1932
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
1933

1934
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
1935
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
1936
                               }),
1✔
1937

1938
            Botan_Tests::CHECK("Expect Server close_notify",
1939
                               [&](Test::Result& result) {
1✔
1940
                                  result.require("ctx is available", ctx != nullptr);
2✔
1941
                                  ctx->server.close();
1✔
1942

1943
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
1944
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
1945
                                  result.test_eq("Server's close notify",
2✔
1946
                                                 ctx->pull_send_buffer(),
2✔
1947
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1948
                               }),
1✔
1949

1950
         };
6✔
1951
      }
1✔
1952

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

1956
         // 32 - for server hello random
1957
         // 32 - for KeyShare (eph. x25519 pair)
1958
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1959

1960
         std::unique_ptr<Server_Context> ctx;
1✔
1961

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

1973
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1974

1975
                                  ctx->check_callback_invocations(result,
16✔
1976
                                                                  "client hello received",
1977
                                                                  {"tls_emit_data",
1978
                                                                   "tls_examine_extensions_client_hello",
1979
                                                                   "tls_modify_extensions_server_hello",
1980
                                                                   "tls_modify_extensions_encrypted_extensions",
1981
                                                                   "tls_modify_extensions_certificate",
1982
                                                                   "tls_sign_message",
1983
                                                                   "tls_generate_ephemeral_key",
1984
                                                                   "tls_ephemeral_key_agreement",
1985
                                                                   "tls_inspect_handshake_msg_client_hello",
1986
                                                                   "tls_inspect_handshake_msg_server_hello",
1987
                                                                   "tls_inspect_handshake_msg_encrypted_extensions",
1988
                                                                   "tls_inspect_handshake_msg_certificate",
1989
                                                                   "tls_inspect_handshake_msg_certificate_verify",
1990
                                                                   "tls_inspect_handshake_msg_finished"});
1991
                               }),
1✔
1992

1993
            Botan_Tests::CHECK("Verify server's generated handshake messages",
1994
                               [&](Test::Result& result) {
1✔
1995
                                  result.require("ctx is available", ctx != nullptr);
2✔
1996
                                  const auto& msgs = ctx->observed_handshake_messages();
1✔
1997

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

2015
                                  // Those records contain the required Change Cipher Spec message the server must produce for compatibility mode compliance
2016
                                  result.test_eq("Server's entire first flight",
3✔
2017
                                                 ctx->pull_send_buffer(),
2✔
2018
                                                 concat(vars.get_req_bin("Record_ServerHello"),
4✔
2019
                                                        vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2020

2021
                                  result.confirm("Server could now send application data", ctx->server.is_active());
3✔
2022
                               }),
1✔
2023

2024
            Botan_Tests::CHECK("Receive Client Finished",
2025
                               [&](Test::Result& result) {
1✔
2026
                                  result.require("ctx is available", ctx != nullptr);
1✔
2027
                                  ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2028

2029
                                  ctx->check_callback_invocations(result,
6✔
2030
                                                                  "client finished received",
2031
                                                                  {"tls_inspect_handshake_msg_finished",
2032
                                                                   "tls_current_timestamp",
2033
                                                                   "tls_session_established",
2034
                                                                   "tls_session_activated"});
2035

2036
                                  result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2037
                               }),
1✔
2038

2039
            Botan_Tests::CHECK("Receive Client close_notify",
2040
                               [&](Test::Result& result) {
1✔
2041
                                  result.require("ctx is available", ctx != nullptr);
1✔
2042
                                  ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2043

2044
                                  ctx->check_callback_invocations(
4✔
2045
                                     result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2046

2047
                                  result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2048
                                  result.confirm("connection is still active", ctx->server.is_active());
2✔
2049
                               }),
1✔
2050

2051
            Botan_Tests::CHECK("Expect Server close_notify",
2052
                               [&](Test::Result& result) {
1✔
2053
                                  result.require("ctx is available", ctx != nullptr);
2✔
2054
                                  ctx->server.close();
1✔
2055

2056
                                  result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2057
                                  result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2058
                                  result.test_eq("Server's close notify",
2✔
2059
                                                 ctx->pull_send_buffer(),
2✔
2060
                                                 vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2061
                               }),
1✔
2062

2063
         };
6✔
2064
      }
1✔
2065
};
2066

2067
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_client", Test_TLS_RFC8448_Client);
2068
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_server", Test_TLS_RFC8448_Server);
2069

2070
#endif
2071

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