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

randombit / botan / 20337522608

18 Dec 2025 12:50PM UTC coverage: 90.555% (+0.2%) from 90.358%
20337522608

Pull #5167

github

web-flow
Merge 4a0197138 into 1fd0d0cf5
Pull Request #5167: Changes to reduce unnecessary inclusions

101518 of 112106 relevant lines covered (90.56%)

12598813.82 hits per line

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

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

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

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

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

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

44
namespace Botan_Tests {
45

46
#if defined(BOTAN_CAN_RUN_TEST_TLS_RFC8448)
47

48
namespace {
49

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

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

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

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

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

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

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

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

103
      explicit Padding(const size_t padding_bytes) : m_padding_bytes(padding_bytes) {}
2✔
104

105
      std::vector<uint8_t> serialize(Botan::TLS::Connection_Side) const override {
5✔
106
         return std::vector<uint8_t>(m_padding_bytes, 0x00);
5✔
107
      }
108

109
      bool empty() const override { return m_padding_bytes == 0; }
5✔
110

111
   private:
112
      size_t m_padding_bytes;
113
};
114

115
using namespace Botan;
116
using namespace Botan::TLS;
117

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

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

127
using Modify_Exts_Fn =
128
   std::function<void(Botan::TLS::Extensions&, Botan::TLS::Connection_Side, Botan::TLS::Handshake_Type)>;
129

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

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

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

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

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

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

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

187
      void tls_session_activated() override {
12✔
188
         count_callback_invocation("tls_session_activated");
12✔
189
         session_activated_called = true;
12✔
190
      }
12✔
191

192
      bool tls_should_persist_resumption_information(const Session&) override {
2✔
193
         count_callback_invocation("tls_should_persist_resumption_information");
2✔
194
         return true;  // should always store the session
2✔
195
      }
196

197
      void tls_verify_cert_chain(const std::vector<Botan::X509_Certificate>& cert_chain,
5✔
198
                                 const std::vector<std::optional<Botan::OCSP::Response>>&,
199
                                 const std::vector<Botan::Certificate_Store*>&,
200
                                 Botan::Usage_Type,
201
                                 std::string_view,
202
                                 const Botan::TLS::Policy&) override {
203
         count_callback_invocation("tls_verify_cert_chain");
5✔
204
         certificate_chain = cert_chain;
5✔
205
      }
5✔
206

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

216
      std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const override {
×
217
         count_callback_invocation("tls_verify_cert_chain");
×
218
         return std::chrono::milliseconds(0);
×
219
      }
220

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

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

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

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

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

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

261
         throw Test_Error("TLS implementation produced an unexpected message to be signed: " + Botan::hex_encode(msg));
×
262
      }
263

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

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

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

288
      void tls_inspect_handshake_msg(const Handshake_Message& message) override {
102✔
289
         count_callback_invocation("tls_inspect_handshake_msg_" + message.type_string());
306✔
290

291
         try {
102✔
292
            auto serialized_message = message.serialize();
102✔
293

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

302
         return Callbacks::tls_inspect_handshake_msg(message);
102✔
303
      }
304

305
      std::string tls_server_choose_app_protocol(const std::vector<std::string>& client_protos) override {
×
306
         count_callback_invocation("tls_server_choose_app_protocol");
×
307
         return Callbacks::tls_server_choose_app_protocol(client_protos);
×
308
      }
309

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

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

325
      std::string tls_peer_network_identity() override {
×
326
         count_callback_invocation("tls_peer_network_identity");
×
327
         return Callbacks::tls_peer_network_identity();
×
328
      }
329

330
      std::chrono::system_clock::time_point tls_current_timestamp() override {
23✔
331
         count_callback_invocation("tls_current_timestamp");
23✔
332
         return m_timestamp;
23✔
333
      }
334

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

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

339
      uint64_t last_received_seq_no() const { return received_seq_no; }
4✔
340

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

343
      void reset_callback_invocation_counters() { m_callback_invocations.clear(); }
60✔
344

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

351
         m_callback_invocations[callback_name]++;
339✔
352
      }
339✔
353

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

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

370
      mutable std::map<std::string, unsigned int> m_callback_invocations;
371
};
372

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

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

388
         m_client_private_key.reset(create_private_key("RSA", *rng, "1024").release());
28✔
389
      }
28✔
390

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

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

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

418
         if(type == "tls-client") {
5✔
419
            return m_client_private_key;
1✔
420
         }
421

422
         if(m_alternative_server_certificate) {
4✔
423
            return m_bogus_alternative_server_private_key;
1✔
424
         }
425

426
         return m_server_private_key;
3✔
427
      }
428

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

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

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

458
         if(prf && prf != epsk.prf_algo()) {
2✔
459
            return {};
×
460
         }
461

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

471
   private:
472
      bool m_alternative_server_certificate;
473
      std::optional<ExternalPSK> m_external_psk;
474
      std::shared_ptr<Private_Key> m_client_private_key;
475
      std::shared_ptr<Private_Key> m_bogus_alternative_server_private_key;
476
      std::shared_ptr<Private_Key> m_server_private_key;
477
};
478

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

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

489
         return Botan::TLS::Text_Policy(is);
14✔
490
      }
14✔
491

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

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

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

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

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

537
         return selected_group != supported_by_us.end() ? *selected_group : Named_Group::NONE;
8✔
538
      }
8✔
539

540
   private:
541
      bool m_rfc8448;
542
};
543

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

565
   public:
566
      RFC8448_Session_Manager() : Session_Manager(std::make_shared<Botan::Null_RNG>()) {}
28✔
567

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

570
      void store(const Session& session, const Session_Handle& handle) override {
4✔
571
         m_sessions.push_back({session, handle});
4✔
572
      }
12✔
573

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

579
         if(m_sessions.size() != 1) {
1✔
580
            throw Test_Error("No mocked session handle available; Test bug?");
×
581
         }
582

583
         const auto& [mocked_session, handle] = m_sessions.front();
1✔
584
         if(mocked_session.master_secret() != session.master_secret()) {
1✔
585
            throw Test_Error("Generated session object does not match the expected mock");
×
586
         }
587

588
         return handle;
1✔
589
      }
590

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

600
      std::vector<Session_with_Handle> find_some(const Server_Information& info, const size_t) override {
7✔
601
         std::vector<Session_with_Handle> found_sessions;
7✔
602
         for(const auto& [session, handle] : m_sessions) {
8✔
603
            if(session.server_info() == info) {
1✔
604
               found_sessions.emplace_back(Session_with_Handle{session, handle});
2✔
605
            }
606
         }
607

608
         return found_sessions;
7✔
609
      }
×
610

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

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

619
   private:
620
      std::vector<Session_with_Handle> m_sessions;
621
};
622

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

651
   public:
652
      virtual ~TLS_Context() = default;
70✔
653

654
      TLS_Context(TLS_Context&) = delete;
655
      TLS_Context& operator=(const TLS_Context&) = delete;
656

657
      TLS_Context(TLS_Context&&) = delete;
658
      TLS_Context& operator=(TLS_Context&&) = delete;
659

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

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

664
      uint64_t last_received_seq_no() const { return m_callbacks->last_received_seq_no(); }
4✔
665

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

680
         for(const auto& invoke : invokes) {
371✔
681
            if(invoke.second == 0) {
311✔
682
               continue;
×
683
            }
684
            result.confirm(
622✔
685
               invoke.first + " was expected (Context: " + context + ")",
1,244✔
686
               std::find(callback_names.cbegin(), callback_names.cend(), invoke.first) != callback_names.cend());
622✔
687
         }
688

689
         m_callbacks->reset_callback_invocation_counters();
60✔
690
      }
60✔
691

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

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

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

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

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

705
   protected:
706
      std::shared_ptr<Test_TLS_13_Callbacks> m_callbacks;  // NOLINT(*-non-private-member-variable*)
707
      std::shared_ptr<Test_Credentials> m_creds;           // NOLINT(*-non-private-member-variable*)
708

709
      std::shared_ptr<Botan::RandomNumberGenerator> m_rng;     // NOLINT(*-non-private-member-variable*)
710
      std::shared_ptr<RFC8448_Session_Manager> m_session_mgr;  // NOLINT(*-non-private-member-variable*)
711
      std::shared_ptr<const RFC8448_Text_Policy> m_policy;     // NOLINT(*-non-private-member-variable*)
712
};
713

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

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

741
      Botan::TLS::Client client;  // NOLINT(*-non-private-member-variable*)
742
};
743

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

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

766
      Botan::TLS::Server server;  // NOLINT(*-non-private-member-variable*)
767
};
768

769
void sort_extensions(Botan::TLS::Extensions& exts, const std::vector<Botan::TLS::Extension_Code>& expected_order) {
30✔
770
   for(const auto ext_type : expected_order) {
283✔
771
      auto ext = exts.take(ext_type);
253✔
772
      if(ext != nullptr) {
253✔
773
         exts.add(std::move(ext));
230✔
774
      }
775
   }
253✔
776
}
30✔
777

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

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

823
void add_early_data_indication(Botan::TLS::Extensions& exts) {
1✔
824
   exts.add(new Botan::TLS::EarlyDataIndication());  // NOLINT(*-owning-memory)
1✔
825
}
1✔
826

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

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

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

841
   mock("Server_MessageToSign", "Server_MessageSignature");
18✔
842
   mock("Client_MessageToSign", "Client_MessageSignature");
18✔
843

844
   return result;
9✔
845
}
×
846

847
}  // namespace
848

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

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

898
      virtual std::string side() const = 0;
899

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

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

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

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

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

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

984
               add_renegotiation_extension(exts);
1✔
985
               sort_rfc8448_extensions(exts, side);
1✔
986
            }
987
         };
1✔
988

989
         std::unique_ptr<Client_Context> ctx;
1✔
990

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

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

1010
                     result.test_eq(
2✔
1011
                        "TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
3✔
1012
                  }),
1✔
1013

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

1022
                     ctx->client.received_data(server_hello_a);
1✔
1023
                     ctx->check_callback_invocations(result, "server hello partially received", {});
2✔
1024

1025
                     ctx->client.received_data(server_hello_b);
1✔
1026
                     ctx->check_callback_invocations(result,
2✔
1027
                                                     "server hello received",
1028
                                                     {"tls_inspect_handshake_msg_server_hello",
1029
                                                      "tls_examine_extensions_server_hello",
1030
                                                      "tls_ephemeral_key_agreement"});
1031

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

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

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

1060
                     result.test_eq("correct handshake finished",
2✔
1061
                                    ctx->pull_send_buffer(),
2✔
1062
                                    vars.get_req_bin("Record_ClientFinished"));
2✔
1063
                  }),
1✔
1064

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

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

1085
            CHECK("Send Application Data",
1086
                  [&](Test::Result& result) {
1✔
1087
                     result.require("ctx is available", ctx != nullptr);
1✔
1088
                     ctx->send(vars.get_req_bin("Client_AppData"));
3✔
1089

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

1092
                     result.test_eq("correct client application data",
2✔
1093
                                    ctx->pull_send_buffer(),
2✔
1094
                                    vars.get_req_bin("Record_Client_AppData"));
2✔
1095
                  }),
1✔
1096

1097
            CHECK("Receive Application Data",
1098
                  [&](Test::Result& result) {
1✔
1099
                     result.require("ctx is available", ctx != nullptr);
1✔
1100
                     ctx->client.received_data(vars.get_req_bin("Record_Server_AppData"));
2✔
1101

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

1104
                     const auto rcvd = ctx->pull_receive_buffer();
1✔
1105
                     result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Server_AppData"));
3✔
1106
                     result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(1));
2✔
1107
                  }),
1✔
1108

1109
            CHECK("Close Connection",
1110
                  [&](Test::Result& result) {
1✔
1111
                     result.require("ctx is available", ctx != nullptr);
1✔
1112
                     ctx->client.close();
1✔
1113

1114
                     result.test_eq(
2✔
1115
                        "close payload", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1116
                     ctx->check_callback_invocations(result, "CLOSE_NOTIFY sent", {"tls_emit_data"});
2✔
1117

1118
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1119
                     ctx->check_callback_invocations(
2✔
1120
                        result, "CLOSE_NOTIFY received", {"tls_alert", "tls_peer_closed_connection"});
1121

1122
                     result.confirm("connection is closed", ctx->client.is_closed());
2✔
1123
                  }),
1✔
1124
         };
8✔
1125
      }
3✔
1126

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

1130
         // 32 - for client hello random
1131
         // 32 - for KeyShare (eph. x25519 key pair)
1132
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1133

1134
         auto add_extensions_and_sort = [](Botan::TLS::Extensions& exts,
2✔
1135
                                           Botan::TLS::Connection_Side side,
1136
                                           Botan::TLS::Handshake_Type which_message) {
1137
            if(which_message == Handshake_Type::ClientHello) {
1✔
1138
               exts.add(new Padding(87));  // NOLINT(*-owning-memory)
1✔
1139

1140
               add_renegotiation_extension(exts);
1✔
1141

1142
               // TODO: Implement early data support and remove this 'hack'.
1143
               //
1144
               // Currently, the production implementation will never add this
1145
               // extension even if the resumed session would allow early data.
1146
               add_early_data_indication(exts);
1✔
1147
               sort_rfc8448_extensions(exts, side);
1✔
1148
            }
1149
         };
1✔
1150

1151
         std::unique_ptr<Client_Context> ctx;
1✔
1152

1153
         return {
1✔
1154
            CHECK("Client Hello",
1155
                  [&](Test::Result& result) {
1✔
1156
                     ctx = std::make_unique<Client_Context>(
1✔
1157
                        std::move(rng),
1158
                        std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
2✔
1159
                        vars.get_req_u64("CurrentTimestamp"),
1✔
1160
                        add_extensions_and_sort,
1161
                        std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
1162
                                  Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1163

1164
                     result.confirm("client not closed", !ctx->client.is_closed());
2✔
1165
                     ctx->check_callback_invocations(result,
2✔
1166
                                                     "client hello prepared",
1167
                                                     {
1168
                                                        "tls_emit_data",
1169
                                                        "tls_inspect_handshake_msg_client_hello",
1170
                                                        "tls_modify_extensions_client_hello",
1171
                                                        "tls_current_timestamp",
1172
                                                        "tls_generate_ephemeral_key",
1173
                                                     });
1174

1175
                     result.test_eq(
2✔
1176
                        "TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
3✔
1177
                  })
1✔
1178

1179
            // TODO: The rest of this test vector requires 0-RTT which is not
1180
            //       yet implemented. For now we can only test the client's
1181
            //       ability to offer a session resumption via PSK.
1182
         };
2✔
1183
      }
2✔
1184

1185
      std::vector<Test::Result> hello_retry_request(const VarMap& vars) override {
1✔
1186
         auto add_extensions_and_sort = [flights = 0](Botan::TLS::Extensions& exts,
3✔
1187
                                                      Botan::TLS::Connection_Side side,
1188
                                                      Botan::TLS::Handshake_Type which_message) mutable {
1189
            if(which_message == Handshake_Type::ClientHello) {
2✔
1190
               ++flights;
2✔
1191

1192
               if(flights == 1) {
2✔
1193
                  add_renegotiation_extension(exts);
1✔
1194
               }
1195

1196
               // For some reason RFC8448 decided to require this (fairly obscure) extension
1197
               // in the second flight of the Client_Hello.
1198
               if(flights == 2) {
2✔
1199
                  exts.add(new Padding(175));  // NOLINT(*-owning-memory)
1✔
1200
               }
1201

1202
               sort_rfc8448_extensions(exts, side);
2✔
1203
            }
1204
         };
2✔
1205

1206
         // Fallback RNG is required to for blinding in ECDH with P-256
1207
         auto& fallback_rng = this->rng();
1✔
1208
         auto rng = std::make_unique<Fixed_Output_RNG>(fallback_rng);
1✔
1209

1210
         // 32 - client hello random
1211
         // 32 - eph. x25519 key pair
1212
         // 32 - eph. P-256 key pair
1213
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1214

1215
         std::unique_ptr<Client_Context> ctx;
1✔
1216

1217
         return {
1✔
1218
            CHECK("Client Hello",
1219
                  [&](Test::Result& result) {
1✔
1220
                     ctx = std::make_unique<Client_Context>(std::move(rng),
1✔
1221
                                                            std::make_shared<RFC8448_Text_Policy>("rfc8448_hrr_client"),
2✔
1222
                                                            vars.get_req_u64("CurrentTimestamp"),
1✔
1223
                                                            add_extensions_and_sort);
1✔
1224
                     result.confirm("client not closed", !ctx->client.is_closed());
2✔
1225

1226
                     ctx->check_callback_invocations(result,
2✔
1227
                                                     "client hello prepared",
1228
                                                     {
1229
                                                        "tls_emit_data",
1230
                                                        "tls_inspect_handshake_msg_client_hello",
1231
                                                        "tls_modify_extensions_client_hello",
1232
                                                        "tls_generate_ephemeral_key",
1233
                                                        "tls_current_timestamp",
1234
                                                     });
1235

1236
                     result.test_eq(
2✔
1237
                        "TLS client hello (1)", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
3✔
1238
                  }),
1✔
1239

1240
            CHECK("Hello Retry Request .. second Client Hello",
1241
                  [&](Test::Result& result) {
1✔
1242
                     result.require("ctx is available", ctx != nullptr);
1✔
1243
                     ctx->client.received_data(vars.get_req_bin("Record_HelloRetryRequest"));
2✔
1244

1245
                     ctx->check_callback_invocations(result,
2✔
1246
                                                     "hello retry request received",
1247
                                                     {
1248
                                                        "tls_emit_data",
1249
                                                        "tls_inspect_handshake_msg_hello_retry_request",
1250
                                                        "tls_examine_extensions_hello_retry_request",
1251
                                                        "tls_inspect_handshake_msg_client_hello",
1252
                                                        "tls_modify_extensions_client_hello",
1253
                                                        "tls_generate_ephemeral_key",
1254
                                                     });
1255

1256
                     result.test_eq(
2✔
1257
                        "TLS client hello (2)", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_2"));
3✔
1258
                  }),
1✔
1259

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

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

1274
            CHECK("Server HS Messages .. Client Finished",
1275
                  [&](Test::Result& result) {
1✔
1276
                     result.require("ctx is available", ctx != nullptr);
1✔
1277
                     ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
1278

1279
                     ctx->check_callback_invocations(result,
2✔
1280
                                                     "encrypted handshake messages received",
1281
                                                     {"tls_inspect_handshake_msg_encrypted_extensions",
1282
                                                      "tls_inspect_handshake_msg_certificate",
1283
                                                      "tls_inspect_handshake_msg_certificate_verify",
1284
                                                      "tls_inspect_handshake_msg_finished",
1285
                                                      "tls_examine_extensions_encrypted_extensions",
1286
                                                      "tls_examine_extensions_certificate",
1287
                                                      "tls_emit_data",
1288
                                                      "tls_current_timestamp",
1289
                                                      "tls_session_established",
1290
                                                      "tls_session_activated",
1291
                                                      "tls_verify_cert_chain",
1292
                                                      "tls_verify_message"});
1293

1294
                     result.test_eq(
2✔
1295
                        "client finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
3✔
1296
                  }),
1✔
1297

1298
            CHECK("Close Connection",
1299
                  [&](Test::Result& result) {
1✔
1300
                     result.require("ctx is available", ctx != nullptr);
1✔
1301
                     ctx->client.close();
1✔
1302
                     ctx->check_callback_invocations(
2✔
1303
                        result, "encrypted handshake messages received", {"tls_emit_data"});
1304
                     result.test_eq(
2✔
1305
                        "client close notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1306

1307
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1308
                     ctx->check_callback_invocations(
2✔
1309
                        result, "encrypted handshake messages received", {"tls_alert", "tls_peer_closed_connection"});
1310

1311
                     result.confirm("connection is closed", ctx->client.is_closed());
2✔
1312
                  }),
1✔
1313
         };
6✔
1314
      }
2✔
1315

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

1319
         // 32 - for client hello random
1320
         // 32 - for eph. x25519 key pair
1321
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1322

1323
         auto add_extensions_and_sort = [&](Botan::TLS::Extensions& exts,
3✔
1324
                                            Botan::TLS::Connection_Side side,
1325
                                            Botan::TLS::Handshake_Type which_message) {
1326
            if(which_message == Handshake_Type::ClientHello) {
2✔
1327
               add_renegotiation_extension(exts);
1✔
1328
               sort_rfc8448_extensions(exts, side);
1✔
1329
            }
1330
         };
1331

1332
         std::unique_ptr<Client_Context> ctx;
1✔
1333

1334
         return {
1✔
1335
            CHECK("Client Hello",
1336
                  [&](Test::Result& result) {
1✔
1337
                     ctx = std::make_unique<Client_Context>(std::move(rng),
1✔
1338
                                                            std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
2✔
1339
                                                            vars.get_req_u64("CurrentTimestamp"),
1✔
1340
                                                            add_extensions_and_sort,
1341
                                                            std::nullopt,
1342
                                                            std::nullopt,
1343
                                                            make_mock_signatures(vars));
3✔
1344

1345
                     ctx->check_callback_invocations(result,
2✔
1346
                                                     "initial callbacks",
1347
                                                     {
1348
                                                        "tls_emit_data",
1349
                                                        "tls_inspect_handshake_msg_client_hello",
1350
                                                        "tls_modify_extensions_client_hello",
1351
                                                        "tls_generate_ephemeral_key",
1352
                                                        "tls_current_timestamp",
1353
                                                     });
1354

1355
                     result.test_eq("Client Hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1356
                  }),
1✔
1357

1358
            CHECK("Server Hello",
1359
                  [&](auto& result) {
1✔
1360
                     result.require("ctx is available", ctx != nullptr);
1✔
1361
                     ctx->client.received_data(vars.get_req_bin("Record_ServerHello"));
2✔
1362

1363
                     ctx->check_callback_invocations(result,
2✔
1364
                                                     "callbacks after server hello",
1365
                                                     {
1366
                                                        "tls_examine_extensions_server_hello",
1367
                                                        "tls_inspect_handshake_msg_server_hello",
1368
                                                        "tls_ephemeral_key_agreement",
1369
                                                     });
1370
                  }),
1✔
1371

1372
            CHECK("other handshake messages and client auth",
1373
                  [&](Test::Result& result) {
1✔
1374
                     result.require("ctx is available", ctx != nullptr);
1✔
1375
                     ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
1376

1377
                     ctx->check_callback_invocations(result,
2✔
1378
                                                     "signing callbacks invoked",
1379
                                                     {
1380
                                                        "tls_sign_message",
1381
                                                        "tls_emit_data",
1382
                                                        "tls_examine_extensions_encrypted_extensions",
1383
                                                        "tls_examine_extensions_certificate",
1384
                                                        "tls_examine_extensions_certificate_request",
1385
                                                        "tls_modify_extensions_certificate",
1386
                                                        "tls_inspect_handshake_msg_certificate",
1387
                                                        "tls_inspect_handshake_msg_certificate_request",
1388
                                                        "tls_inspect_handshake_msg_certificate_verify",
1389
                                                        "tls_inspect_handshake_msg_encrypted_extensions",
1390
                                                        "tls_inspect_handshake_msg_finished",
1391
                                                        "tls_current_timestamp",
1392
                                                        "tls_session_established",
1393
                                                        "tls_session_activated",
1394
                                                        "tls_verify_cert_chain",
1395
                                                        "tls_verify_message",
1396
                                                     });
1397

1398
                     // ClientFinished contains the entire coalesced client authentication flight
1399
                     // Messages: Certificate, CertificateVerify, Finished
1400
                     result.test_eq(
2✔
1401
                        "Client Auth and Finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
3✔
1402
                  }),
1✔
1403

1404
            CHECK("Close Connection",
1405
                  [&](Test::Result& result) {
1✔
1406
                     result.require("ctx is available", ctx != nullptr);
1✔
1407
                     ctx->client.close();
1✔
1408
                     result.test_eq(
2✔
1409
                        "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1410

1411
                     ctx->check_callback_invocations(result,
2✔
1412
                                                     "after sending close notify",
1413
                                                     {
1414
                                                        "tls_emit_data",
1415
                                                     });
1416

1417
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1418
                     result.confirm("connection closed", ctx->client.is_closed());
2✔
1419

1420
                     ctx->check_callback_invocations(
2✔
1421
                        result, "after receiving close notify", {"tls_alert", "tls_peer_closed_connection"});
1422
                  }),
1✔
1423
         };
5✔
1424
      }
2✔
1425

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

1429
         // 32 - client hello random
1430
         // 32 - legacy session ID
1431
         // 32 - eph. x25519 key pair
1432
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1433

1434
         auto add_extensions_and_sort = [&](Botan::TLS::Extensions& exts,
2✔
1435
                                            Botan::TLS::Connection_Side side,
1436
                                            Botan::TLS::Handshake_Type which_message) {
1437
            if(which_message == Handshake_Type::ClientHello) {
1✔
1438
               add_renegotiation_extension(exts);
1✔
1439
               sort_rfc8448_extensions(exts, side);
1✔
1440
            }
1441
         };
1442

1443
         std::unique_ptr<Client_Context> ctx;
1✔
1444

1445
         return {
1✔
1446
            CHECK("Client Hello",
1447
                  [&](Test::Result& result) {
1✔
1448
                     ctx =
1✔
1449
                        std::make_unique<Client_Context>(std::move(rng),
1✔
1450
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_compat_client"),
2✔
1451
                                                         vars.get_req_u64("CurrentTimestamp"),
1✔
1452
                                                         add_extensions_and_sort);
1✔
1453

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

1456
                     ctx->check_callback_invocations(result,
2✔
1457
                                                     "client hello prepared",
1458
                                                     {
1459
                                                        "tls_emit_data",
1460
                                                        "tls_inspect_handshake_msg_client_hello",
1461
                                                        "tls_modify_extensions_client_hello",
1462
                                                        "tls_generate_ephemeral_key",
1463
                                                        "tls_current_timestamp",
1464
                                                     });
1465
                  }),
1✔
1466

1467
            CHECK("Server Hello + other handshake messages",
1468
                  [&](Test::Result& result) {
1✔
1469
                     result.require("ctx is available", ctx != nullptr);
1✔
1470
                     ctx->client.received_data(
2✔
1471
                        Botan::concat(vars.get_req_bin("Record_ServerHello"),
4✔
1472
                                      // ServerHandshakeMessages contains the expected ChangeCipherSpec record
1473
                                      vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1474

1475
                     ctx->check_callback_invocations(result,
2✔
1476
                                                     "callbacks after server's first flight",
1477
                                                     {
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
                                                        "tls_examine_extensions_server_hello",
1484
                                                        "tls_examine_extensions_encrypted_extensions",
1485
                                                        "tls_examine_extensions_certificate",
1486
                                                        "tls_emit_data",
1487
                                                        "tls_current_timestamp",
1488
                                                        "tls_session_established",
1489
                                                        "tls_session_activated",
1490
                                                        "tls_verify_cert_chain",
1491
                                                        "tls_verify_message",
1492
                                                        "tls_ephemeral_key_agreement",
1493
                                                     });
1494

1495
                     result.test_eq("CCS + Client Finished",
2✔
1496
                                    ctx->pull_send_buffer(),
2✔
1497
                                    // ClientFinished contains the expected ChangeCipherSpec record
1498
                                    vars.get_req_bin("Record_ClientFinished"));
2✔
1499

1500
                     result.confirm("client is ready to send application traffic", ctx->client.is_active());
2✔
1501
                     result.confirm("handshake is complete", ctx->client.is_handshake_complete());
2✔
1502
                  }),
1✔
1503

1504
            CHECK("Close connection",
1505
                  [&](Test::Result& result) {
1✔
1506
                     result.require("ctx is available", ctx != nullptr);
1✔
1507
                     ctx->client.close();
1✔
1508

1509
                     result.test_eq(
2✔
1510
                        "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1511

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

1516
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1517

1518
                     result.confirm("client connection was terminated", ctx->client.is_closed());
2✔
1519
                  }),
1✔
1520
         };
4✔
1521
      }
2✔
1522

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

1526
         // 32 - for client hello random
1527
         // 32 - for KeyShare (eph. x25519 key pair)
1528
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1529

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

1549
         std::unique_ptr<Client_Context> ctx;
1✔
1550

1551
         return {
1✔
1552
            CHECK("Client Hello",
1553
                  [&](Test::Result& result) {
1✔
1554
                     ctx = std::make_unique<Client_Context>(
1✔
1555
                        std::move(rng),
1556
                        std::make_shared<RFC8448_Text_Policy>("rfc8448_psk_dhe", false /* no rfc8448 */),
2✔
1557
                        vars.get_req_u64("CurrentTimestamp"),
1✔
1558
                        sort_our_extensions,
1559
                        std::nullopt,
1560
                        ExternalPSK(vars.get_req_str("PskIdentity"),
2✔
1561
                                    vars.get_req_str("PskPRF"),
2✔
1562
                                    lock(vars.get_req_bin("PskSecret"))));
5✔
1563

1564
                     result.confirm("client not closed", !ctx->client.is_closed());
2✔
1565
                     ctx->check_callback_invocations(result,
2✔
1566
                                                     "client hello prepared",
1567
                                                     {
1568
                                                        "tls_emit_data",
1569
                                                        "tls_inspect_handshake_msg_client_hello",
1570
                                                        "tls_modify_extensions_client_hello",
1571
                                                        "tls_current_timestamp",
1572
                                                        "tls_generate_ephemeral_key",
1573
                                                     });
1574

1575
                     result.test_eq(
2✔
1576
                        "TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
3✔
1577
                  }),
1✔
1578

1579
            CHECK("Server Hello",
1580
                  [&](Test::Result& result) {
1✔
1581
                     result.require("ctx is available", ctx != nullptr);
1✔
1582
                     const auto server_hello = vars.get_req_bin("Record_ServerHello");
1✔
1583
                     ctx->client.received_data(server_hello);
1✔
1584
                     ctx->check_callback_invocations(result,
2✔
1585
                                                     "server hello received",
1586
                                                     {"tls_inspect_handshake_msg_server_hello",
1587
                                                      "tls_examine_extensions_server_hello",
1588
                                                      "tls_ephemeral_key_agreement"});
1589

1590
                     result.confirm("client is not yet active", !ctx->client.is_active());
2✔
1591
                     result.confirm("handshake is not yet complete", !ctx->client.is_handshake_complete());
2✔
1592
                  }),
1✔
1593

1594
            CHECK(
1595
               "Server HS messages .. Client Finished",
1596
               [&](Test::Result& result) {
1✔
1597
                  result.require("ctx is available", ctx != nullptr);
1✔
1598
                  ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
1599

1600
                  ctx->check_callback_invocations(result,
2✔
1601
                                                  "encrypted handshake messages received",
1602
                                                  {"tls_inspect_handshake_msg_encrypted_extensions",
1603
                                                   "tls_inspect_handshake_msg_finished",
1604
                                                   "tls_examine_extensions_encrypted_extensions",
1605
                                                   "tls_emit_data",
1606
                                                   "tls_current_timestamp",
1607
                                                   "tls_session_established",
1608
                                                   "tls_session_activated"});
1609
                  result.require("PSK negotiated", ctx->psk_identity_negotiated() == vars.get_req_str("PskIdentity"));
2✔
1610
                  result.require("client is active", ctx->client.is_active());
1✔
1611
                  result.confirm("handshake is complete", ctx->client.is_handshake_complete());
2✔
1612

1613
                  result.test_eq(
2✔
1614
                     "correct handshake finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
3✔
1615
               }),
1✔
1616

1617
            CHECK("Send Application Data",
1618
                  [&](Test::Result& result) {
1✔
1619
                     result.require("ctx is available", ctx != nullptr);
1✔
1620
                     ctx->send(vars.get_req_bin("Client_AppData"));
3✔
1621

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

1624
                     result.test_eq("correct client application data",
2✔
1625
                                    ctx->pull_send_buffer(),
2✔
1626
                                    vars.get_req_bin("Record_Client_AppData"));
2✔
1627
                  }),
1✔
1628

1629
            CHECK("Receive Application Data",
1630
                  [&](Test::Result& result) {
1✔
1631
                     result.require("ctx is available", ctx != nullptr);
1✔
1632
                     ctx->client.received_data(vars.get_req_bin("Record_Server_AppData"));
2✔
1633

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

1636
                     const auto rcvd = ctx->pull_receive_buffer();
1✔
1637
                     result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Server_AppData"));
3✔
1638
                     result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
2✔
1639
                  }),
1✔
1640

1641
            CHECK("Close Connection",
1642
                  [&](Test::Result& result) {
1✔
1643
                     result.require("ctx is available", ctx != nullptr);
1✔
1644
                     ctx->client.close();
1✔
1645

1646
                     result.test_eq(
2✔
1647
                        "close payload", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1648
                     ctx->check_callback_invocations(result, "CLOSE_NOTIFY sent", {"tls_emit_data"});
2✔
1649

1650
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1651
                     ctx->check_callback_invocations(
2✔
1652
                        result, "CLOSE_NOTIFY received", {"tls_alert", "tls_peer_closed_connection"});
1653

1654
                     result.confirm("connection is closed", ctx->client.is_closed());
2✔
1655
                  }),
1✔
1656
         };
7✔
1657
      }
2✔
1658

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

1662
         // 32 - for client hello random
1663
         // 32 - for KeyShare (eph. x25519 key pair)
1664
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1665

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

1687
         std::unique_ptr<Client_Context> ctx;
1✔
1688

1689
         return {
1✔
1690
            CHECK("Client Hello",
1691
                  [&](Test::Result& result) {
1✔
1692
                     ctx = std::make_unique<Client_Context>(std::move(rng),
1✔
1693
                                                            std::make_shared<RFC8448_Text_Policy>("rfc8448_rawpubkey"),
2✔
1694
                                                            vars.get_req_u64("CurrentTimestamp"),
1✔
1695
                                                            sort_our_extensions,
1696
                                                            std::nullopt,
1697
                                                            std::nullopt,
1698
                                                            make_mock_signatures(vars));
3✔
1699

1700
                     ctx->check_callback_invocations(result,
2✔
1701
                                                     "initial callbacks",
1702
                                                     {
1703
                                                        "tls_emit_data",
1704
                                                        "tls_inspect_handshake_msg_client_hello",
1705
                                                        "tls_modify_extensions_client_hello",
1706
                                                        "tls_generate_ephemeral_key",
1707
                                                        "tls_current_timestamp",
1708
                                                     });
1709

1710
                     result.test_eq("Client Hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1711
                  }),
1✔
1712

1713
            CHECK("Server Hello",
1714
                  [&](auto& result) {
1✔
1715
                     result.require("ctx is available", ctx != nullptr);
1✔
1716
                     ctx->client.received_data(vars.get_req_bin("Record_ServerHello"));
2✔
1717

1718
                     ctx->check_callback_invocations(result,
2✔
1719
                                                     "callbacks after server hello",
1720
                                                     {
1721
                                                        "tls_examine_extensions_server_hello",
1722
                                                        "tls_inspect_handshake_msg_server_hello",
1723
                                                        "tls_ephemeral_key_agreement",
1724
                                                     });
1725
                  }),
1✔
1726

1727
            CHECK("other handshake messages and client auth",
1728
                  [&](Test::Result& result) {
1✔
1729
                     result.require("ctx is available", ctx != nullptr);
1✔
1730
                     ctx->client.received_data(vars.get_req_bin("Record_ServerHandshakeMessages"));
2✔
1731

1732
                     ctx->check_callback_invocations(result,
2✔
1733
                                                     "signing callbacks invoked",
1734
                                                     {
1735
                                                        "tls_sign_message",
1736
                                                        "tls_emit_data",
1737
                                                        "tls_examine_extensions_encrypted_extensions",
1738
                                                        "tls_examine_extensions_certificate",
1739
                                                        "tls_examine_extensions_certificate_request",
1740
                                                        "tls_modify_extensions_certificate",
1741
                                                        "tls_inspect_handshake_msg_certificate",
1742
                                                        "tls_inspect_handshake_msg_certificate_request",
1743
                                                        "tls_inspect_handshake_msg_certificate_verify",
1744
                                                        "tls_inspect_handshake_msg_encrypted_extensions",
1745
                                                        "tls_inspect_handshake_msg_finished",
1746
                                                        "tls_current_timestamp",
1747
                                                        "tls_session_established",
1748
                                                        "tls_session_activated",
1749
                                                        "tls_verify_raw_public_key",
1750
                                                        "tls_verify_message",
1751
                                                     });
1752

1753
                     const auto raw_pk = ctx->client.peer_raw_public_key();
1✔
1754
                     result.confirm(
2✔
1755
                        "Received server's raw public key",
1756
                        raw_pk && raw_pk->fingerprint_public() == server_raw_public_key_pair()->fingerprint_public());
5✔
1757

1758
                     // ClientFinished contains the entire coalesced client authentication flight
1759
                     // Messages: Certificate, CertificateVerify, Finished
1760
                     result.test_eq(
2✔
1761
                        "Client Auth and Finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
3✔
1762
                  }),
1✔
1763

1764
            CHECK("Close Connection",
1765
                  [&](Test::Result& result) {
1✔
1766
                     result.require("ctx is available", ctx != nullptr);
1✔
1767
                     ctx->client.close();
1✔
1768
                     result.test_eq(
2✔
1769
                        "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1770

1771
                     ctx->check_callback_invocations(result,
2✔
1772
                                                     "after sending close notify",
1773
                                                     {
1774
                                                        "tls_emit_data",
1775
                                                     });
1776

1777
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1778
                     result.confirm("connection closed", ctx->client.is_closed());
2✔
1779

1780
                     ctx->check_callback_invocations(
2✔
1781
                        result, "after receiving close notify", {"tls_alert", "tls_peer_closed_connection"});
1782
                  }),
1✔
1783
         };
5✔
1784
      }
2✔
1785
};
1786

1787
class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 {
1✔
1788
   private:
1789
      std::string side() const override { return "Server"; }
7✔
1790

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

1794
         // 32 - for server hello random
1795
         // 32 - for KeyShare (eph. x25519 key pair)  --  I guess?
1796
         //  4 - for ticket_age_add (in New Session Ticket)
1797
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1798

1799
         std::unique_ptr<Server_Context> ctx;
1✔
1800

1801
         return {
1✔
1802
            CHECK("Send Client Hello",
1803
                  [&](Test::Result& result) {
1✔
1804
                     auto add_early_data_and_sort = [&](Botan::TLS::Extensions& exts,
5✔
1805
                                                        Botan::TLS::Connection_Side side,
1806
                                                        Botan::TLS::Handshake_Type type) {
1807
                        if(type == Handshake_Type::NewSessionTicket) {
4✔
1808
                           exts.add(new EarlyDataIndication(1024));  // NOLINT(*-owning-memory)
1✔
1809
                        }
1810
                        sort_rfc8448_extensions(exts, side, type);
4✔
1811
                     };
4✔
1812

1813
                     ctx = std::make_unique<Server_Context>(
1✔
1814
                        std::move(rng),
1815
                        std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
2✔
1816
                        vars.get_req_u64("CurrentTimestamp"),
1✔
1817
                        add_early_data_and_sort,
1818
                        make_mock_signatures(vars),
1✔
1819
                        false,
2✔
1820
                        std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
1821
                                  Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1822
                     result.confirm("server not closed", !ctx->server.is_closed());
2✔
1823

1824
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1825

1826
                     ctx->check_callback_invocations(result,
2✔
1827
                                                     "client hello received",
1828
                                                     {"tls_emit_data",
1829
                                                      "tls_examine_extensions_client_hello",
1830
                                                      "tls_modify_extensions_server_hello",
1831
                                                      "tls_modify_extensions_encrypted_extensions",
1832
                                                      "tls_modify_extensions_certificate",
1833
                                                      "tls_sign_message",
1834
                                                      "tls_generate_ephemeral_key",
1835
                                                      "tls_ephemeral_key_agreement",
1836
                                                      "tls_inspect_handshake_msg_client_hello",
1837
                                                      "tls_inspect_handshake_msg_server_hello",
1838
                                                      "tls_inspect_handshake_msg_encrypted_extensions",
1839
                                                      "tls_inspect_handshake_msg_certificate",
1840
                                                      "tls_inspect_handshake_msg_certificate_verify",
1841
                                                      "tls_inspect_handshake_msg_finished"});
1842
                  }),
1✔
1843

1844
            CHECK("Verify generated messages in server's first flight",
1845
                  [&](Test::Result& result) {
1✔
1846
                     result.require("ctx is available", ctx != nullptr);
1✔
1847
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
1848

1849
                     result.test_eq("Server Hello",
3✔
1850
                                    msgs.at("server_hello")[0],
2✔
1851
                                    strip_message_header(vars.get_opt_bin("Message_ServerHello")));
3✔
1852
                     result.test_eq("Encrypted Extensions",
3✔
1853
                                    msgs.at("encrypted_extensions")[0],
2✔
1854
                                    strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
1855
                     result.test_eq("Certificate",
3✔
1856
                                    msgs.at("certificate")[0],
2✔
1857
                                    strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
1858
                     result.test_eq("CertificateVerify",
3✔
1859
                                    msgs.at("certificate_verify")[0],
2✔
1860
                                    strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
1861

1862
                     result.test_eq("Server's entire first flight",
2✔
1863
                                    ctx->pull_send_buffer(),
2✔
1864
                                    concat(vars.get_req_bin("Record_ServerHello"),
4✔
1865
                                           vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1866

1867
                     // Note: is_active() defines that we can send application data.
1868
                     //       RFC 8446 Section 4.4.4 explicitly allows that for servers
1869
                     //       that did not receive the client's Finished message, yet.
1870
                     //       However, before receiving and validating this message,
1871
                     //       the handshake is not yet finished.
1872
                     result.confirm("Server can now send application data", ctx->server.is_active());
2✔
1873
                     result.confirm("handshake is not yet complete", !ctx->server.is_handshake_complete());
2✔
1874
                  }),
1✔
1875

1876
            CHECK("Send Client Finished",
1877
                  [&](Test::Result& result) {
1✔
1878
                     result.require("ctx is available", ctx != nullptr);
1✔
1879
                     ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
1880

1881
                     ctx->check_callback_invocations(result,
2✔
1882
                                                     "client finished received",
1883
                                                     {"tls_inspect_handshake_msg_finished",
1884
                                                      "tls_current_timestamp",
1885
                                                      "tls_session_established",
1886
                                                      "tls_session_activated"});
1887
                  }),
1✔
1888

1889
            CHECK("Send Session Ticket",
1890
                  [&](Test::Result& result) {
1✔
1891
                     result.require("ctx is available", ctx != nullptr);
1✔
1892
                     const auto new_tickets = ctx->server.send_new_session_tickets(1);
1✔
1893

1894
                     result.test_eq("session ticket was sent", new_tickets, 1);
1✔
1895

1896
                     ctx->check_callback_invocations(result,
2✔
1897
                                                     "issued new session ticket",
1898
                                                     {"tls_inspect_handshake_msg_new_session_ticket",
1899
                                                      "tls_current_timestamp",
1900
                                                      "tls_emit_data",
1901
                                                      "tls_modify_extensions_new_session_ticket",
1902
                                                      "tls_should_persist_resumption_information"});
1903
                  }),
1✔
1904

1905
            CHECK("Verify generated new session ticket message",
1906
                  [&](Test::Result& result) {
1✔
1907
                     result.require("ctx is available", ctx != nullptr);
1✔
1908
                     result.test_eq(
2✔
1909
                        "New Session Ticket", ctx->pull_send_buffer(), vars.get_req_bin("Record_NewSessionTicket"));
3✔
1910
                  }),
1✔
1911

1912
            CHECK("Receive Application Data",
1913
                  [&](Test::Result& result) {
1✔
1914
                     result.require("ctx is available", ctx != nullptr);
1✔
1915
                     ctx->server.received_data(vars.get_req_bin("Record_Client_AppData"));
2✔
1916
                     ctx->check_callback_invocations(result, "application data received", {"tls_record_received"});
2✔
1917

1918
                     const auto rcvd = ctx->pull_receive_buffer();
1✔
1919
                     result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Client_AppData"));
3✔
1920
                     result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
2✔
1921
                  }),
1✔
1922

1923
            CHECK("Send Application Data",
1924
                  [&](Test::Result& result) {
1✔
1925
                     result.require("ctx is available", ctx != nullptr);
1✔
1926
                     ctx->send(vars.get_req_bin("Server_AppData"));
3✔
1927

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

1930
                     result.test_eq("correct server application data",
2✔
1931
                                    ctx->pull_send_buffer(),
2✔
1932
                                    vars.get_req_bin("Record_Server_AppData"));
2✔
1933
                  }),
1✔
1934

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

1940
                     ctx->check_callback_invocations(
2✔
1941
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
1942

1943
                     result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
1944
                     result.confirm("connection is still active", ctx->server.is_active());
2✔
1945
                     result.confirm("handshake is still finished", ctx->server.is_handshake_complete());
2✔
1946
                  }),
1✔
1947

1948
            CHECK("Expect Server close_notify",
1949
                  [&](Test::Result& result) {
1✔
1950
                     result.require("ctx is available", ctx != nullptr);
1✔
1951
                     ctx->server.close();
1✔
1952

1953
                     result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
1954
                     result.confirm("connection is now closed", ctx->server.is_closed());
2✔
1955
                     result.confirm("handshake is still finished", ctx->server.is_handshake_complete());
2✔
1956
                     result.test_eq("Server's close notify",
2✔
1957
                                    ctx->pull_send_buffer(),
2✔
1958
                                    vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1959
                  }),
1✔
1960
         };
10✔
1961
      }
2✔
1962

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

1966
         // 32 - for server hello random
1967
         // 32 - for KeyShare (eph. x25519 key pair)
1968
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1969

1970
         std::unique_ptr<Server_Context> ctx;
1✔
1971

1972
         return {
1✔
1973
            CHECK("Receive Client Hello",
1974
                  [&](Test::Result& result) {
1✔
1975
                     auto add_cookie_and_sort = [&](Botan::TLS::Extensions& exts,
3✔
1976
                                                    Botan::TLS::Connection_Side side,
1977
                                                    Botan::TLS::Handshake_Type type) {
1978
                        if(type == Handshake_Type::EncryptedExtensions) {
2✔
1979
                           exts.add(new EarlyDataIndication());  // NOLINT(*-owning-memory)
1✔
1980
                        }
1981
                        sort_rfc8448_extensions(exts, side, type);
2✔
1982
                     };
2✔
1983

1984
                     ctx = std::make_unique<Server_Context>(
1✔
1985
                        std::move(rng),
1986
                        std::make_shared<RFC8448_Text_Policy>("rfc8448_1rtt"),
2✔
1987
                        vars.get_req_u64("CurrentTimestamp"),
1✔
1988
                        add_cookie_and_sort,
1989
                        make_mock_signatures(vars),
1✔
1990
                        false,
2✔
1991
                        std::pair{Botan::TLS::Session(vars.get_req_bin("Client_SessionData")),
5✔
1992
                                  Botan::TLS::Session_Ticket(vars.get_req_bin("SessionTicket"))});
3✔
1993
                     result.confirm("server not closed", !ctx->server.is_closed());
2✔
1994

1995
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1996

1997
                     ctx->check_callback_invocations(result,
2✔
1998
                                                     "client hello received",
1999
                                                     {
2000
                                                        "tls_emit_data",
2001
                                                        "tls_current_timestamp",
2002
                                                        "tls_generate_ephemeral_key",
2003
                                                        "tls_ephemeral_key_agreement",
2004
                                                        "tls_examine_extensions_client_hello",
2005
                                                        "tls_modify_extensions_server_hello",
2006
                                                        "tls_modify_extensions_encrypted_extensions",
2007
                                                        "tls_inspect_handshake_msg_client_hello",
2008
                                                        "tls_inspect_handshake_msg_server_hello",
2009
                                                        "tls_inspect_handshake_msg_encrypted_extensions",
2010
                                                        "tls_inspect_handshake_msg_finished",
2011
                                                     });
2012
                  }),
1✔
2013

2014
            CHECK("Verify generated messages in server's first flight",
2015
                  [&](Test::Result& result) {
1✔
2016
                     result.require("ctx is available", ctx != nullptr);
1✔
2017
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
2018

2019
                     result.test_eq("Server Hello",
3✔
2020
                                    msgs.at("server_hello")[0],
2✔
2021
                                    strip_message_header(vars.get_opt_bin("Message_ServerHello")));
3✔
2022
                     result.test_eq("Encrypted Extensions",
3✔
2023
                                    msgs.at("encrypted_extensions")[0],
2✔
2024
                                    strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2025

2026
                     result.test_eq("Server's entire first flight",
2✔
2027
                                    ctx->pull_send_buffer(),
2✔
2028
                                    concat(vars.get_req_bin("Record_ServerHello"),
4✔
2029
                                           vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2030

2031
                     // Note: is_active() defines that we can send application data.
2032
                     //       RFC 8446 Section 4.4.4 explicitly allows that for servers
2033
                     //       that did not receive the client's Finished message, yet.
2034
                     //       However, before receiving and validating this message,
2035
                     //       the handshake is not yet finished.
2036
                     result.confirm("Server can now send application data", ctx->server.is_active());
2✔
2037
                     result.confirm("handshake is not yet complete", !ctx->server.is_handshake_complete());
2✔
2038
                  }),
1✔
2039

2040
            // TODO: The rest of this test vector requires 0-RTT which is not
2041
            //       yet implemented. For now we can only test the server's
2042
            //       ability to acknowledge a session resumption via PSK.
2043
         };
3✔
2044
      }
2✔
2045

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

2051
         // 32 - for server hello random
2052
         // 32 - for KeyShare (eph. P-256 key pair)
2053
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2054

2055
         std::unique_ptr<Server_Context> ctx;
1✔
2056

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

2071
                     ctx = std::make_unique<Server_Context>(std::move(rng),
1✔
2072
                                                            std::make_shared<RFC8448_Text_Policy>("rfc8448_hrr_server"),
2✔
2073
                                                            vars.get_req_u64("CurrentTimestamp"),
1✔
2074
                                                            add_cookie_and_sort,
2075
                                                            make_mock_signatures(vars));
3✔
2076
                     result.confirm("server not closed", !ctx->server.is_closed());
2✔
2077

2078
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2079

2080
                     ctx->check_callback_invocations(result,
2✔
2081
                                                     "client hello received",
2082
                                                     {"tls_emit_data",
2083
                                                      "tls_examine_extensions_client_hello",
2084
                                                      "tls_modify_extensions_hello_retry_request",
2085
                                                      "tls_inspect_handshake_msg_client_hello",
2086
                                                      "tls_inspect_handshake_msg_hello_retry_request"});
2087
                  }),
1✔
2088

2089
            CHECK("Verify generated Hello Retry Request message",
2090
                  [&](Test::Result& result) {
1✔
2091
                     result.require("ctx is available", ctx != nullptr);
1✔
2092
                     result.test_eq("Server's Hello Retry Request record",
2✔
2093
                                    ctx->pull_send_buffer(),
2✔
2094
                                    vars.get_req_bin("Record_HelloRetryRequest"));
2✔
2095
                     result.confirm("TLS handshake not yet finished", !ctx->server.is_active());
2✔
2096
                     result.confirm("handshake is not yet complete", !ctx->server.is_handshake_complete());
2✔
2097
                  }),
1✔
2098

2099
            CHECK("Receive updated Client Hello message",
2100
                  [&](Test::Result& result) {
1✔
2101
                     result.require("ctx is available", ctx != nullptr);
1✔
2102
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_2"));
2✔
2103

2104
                     ctx->check_callback_invocations(result,
2✔
2105
                                                     "updated client hello received",
2106
                                                     {"tls_emit_data",
2107
                                                      "tls_examine_extensions_client_hello",
2108
                                                      "tls_modify_extensions_server_hello",
2109
                                                      "tls_modify_extensions_encrypted_extensions",
2110
                                                      "tls_modify_extensions_certificate",
2111
                                                      "tls_sign_message",
2112
                                                      "tls_generate_ephemeral_key",
2113
                                                      "tls_ephemeral_key_agreement",
2114
                                                      "tls_inspect_handshake_msg_client_hello",
2115
                                                      "tls_inspect_handshake_msg_server_hello",
2116
                                                      "tls_inspect_handshake_msg_encrypted_extensions",
2117
                                                      "tls_inspect_handshake_msg_certificate",
2118
                                                      "tls_inspect_handshake_msg_certificate_verify",
2119
                                                      "tls_inspect_handshake_msg_finished"});
2120
                  }),
1✔
2121

2122
            CHECK("Verify generated messages in server's second flight",
2123
                  [&](Test::Result& result) {
1✔
2124
                     result.require("ctx is available", ctx != nullptr);
1✔
2125
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
2126

2127
                     result.test_eq("Server Hello",
3✔
2128
                                    msgs.at("server_hello")[0],
2✔
2129
                                    strip_message_header(vars.get_opt_bin("Message_ServerHello")));
3✔
2130
                     result.test_eq("Encrypted Extensions",
3✔
2131
                                    msgs.at("encrypted_extensions")[0],
2✔
2132
                                    strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2133
                     result.test_eq("Certificate",
3✔
2134
                                    msgs.at("certificate")[0],
2✔
2135
                                    strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
2136
                     result.test_eq("CertificateVerify",
3✔
2137
                                    msgs.at("certificate_verify")[0],
2✔
2138
                                    strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
2139
                     result.test_eq("Finished",
3✔
2140
                                    msgs.at("finished")[0],
2✔
2141
                                    strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2142

2143
                     result.test_eq("Server's entire second flight",
2✔
2144
                                    ctx->pull_send_buffer(),
2✔
2145
                                    concat(vars.get_req_bin("Record_ServerHello"),
4✔
2146
                                           vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2147
                     result.confirm("Server could now send application data", ctx->server.is_active());
2✔
2148
                     result.confirm("handshake is not yet complete",
1✔
2149
                                    !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2150
                  }),
1✔
2151

2152
            CHECK("Receive Client Finished",
2153
                  [&](Test::Result& result) {
1✔
2154
                     result.require("ctx is available", ctx != nullptr);
1✔
2155
                     ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2156

2157
                     ctx->check_callback_invocations(result,
2✔
2158
                                                     "client finished received",
2159
                                                     {"tls_inspect_handshake_msg_finished",
2160
                                                      "tls_current_timestamp",
2161
                                                      "tls_session_established",
2162
                                                      "tls_session_activated"});
2163

2164
                     result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2165
                     result.confirm("handshake is complete", ctx->server.is_handshake_complete());
2✔
2166
                  }),
1✔
2167

2168
            CHECK("Receive Client close_notify",
2169
                  [&](Test::Result& result) {
1✔
2170
                     result.require("ctx is available", ctx != nullptr);
1✔
2171
                     ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2172

2173
                     ctx->check_callback_invocations(
2✔
2174
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2175

2176
                     result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2177
                     result.confirm("connection is still active", ctx->server.is_active());
2✔
2178
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2179
                  }),
1✔
2180

2181
            CHECK("Expect Server close_notify",
2182
                  [&](Test::Result& result) {
1✔
2183
                     result.require("ctx is available", ctx != nullptr);
1✔
2184
                     ctx->server.close();
1✔
2185

2186
                     result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2187
                     result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2188
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2189
                     result.test_eq("Server's close notify",
2✔
2190
                                    ctx->pull_send_buffer(),
2✔
2191
                                    vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2192
                  }),
1✔
2193

2194
         };
8✔
2195
      }
2✔
2196

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

2200
         // 32 - for server hello random
2201
         // 32 - for KeyShare (eph. x25519 pair)
2202
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2203

2204
         std::unique_ptr<Server_Context> ctx;
1✔
2205

2206
         return {
1✔
2207
            CHECK("Receive Client Hello",
2208
                  [&](Test::Result& result) {
1✔
2209
                     ctx = std::make_unique<Server_Context>(
1✔
2210
                        std::move(rng),
2211
                        std::make_shared<RFC8448_Text_Policy>("rfc8448_client_auth_server"),
2✔
2212
                        vars.get_req_u64("CurrentTimestamp"),
1✔
2213
                        sort_rfc8448_extensions,
2214
                        make_mock_signatures(vars),
1✔
2215
                        true /* use alternative certificate */);
2✔
2216
                     result.confirm("server not closed", !ctx->server.is_closed());
2✔
2217

2218
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2219

2220
                     ctx->check_callback_invocations(result,
2✔
2221
                                                     "client hello received",
2222
                                                     {"tls_emit_data",
2223
                                                      "tls_examine_extensions_client_hello",
2224
                                                      "tls_modify_extensions_server_hello",
2225
                                                      "tls_modify_extensions_encrypted_extensions",
2226
                                                      "tls_modify_extensions_certificate_request",
2227
                                                      "tls_modify_extensions_certificate",
2228
                                                      "tls_sign_message",
2229
                                                      "tls_generate_ephemeral_key",
2230
                                                      "tls_ephemeral_key_agreement",
2231
                                                      "tls_inspect_handshake_msg_client_hello",
2232
                                                      "tls_inspect_handshake_msg_server_hello",
2233
                                                      "tls_inspect_handshake_msg_encrypted_extensions",
2234
                                                      "tls_inspect_handshake_msg_certificate_request",
2235
                                                      "tls_inspect_handshake_msg_certificate",
2236
                                                      "tls_inspect_handshake_msg_certificate_verify",
2237
                                                      "tls_inspect_handshake_msg_finished"});
2238
                  }),
1✔
2239

2240
            CHECK("Verify server's generated handshake messages",
2241
                  [&](Test::Result& result) {
1✔
2242
                     result.require("ctx is available", ctx != nullptr);
1✔
2243
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
2244

2245
                     result.test_eq("Server Hello",
3✔
2246
                                    msgs.at("server_hello")[0],
2✔
2247
                                    strip_message_header(vars.get_opt_bin("Message_ServerHello")));
3✔
2248
                     result.test_eq("Encrypted Extensions",
3✔
2249
                                    msgs.at("encrypted_extensions")[0],
2✔
2250
                                    strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2251
                     result.test_eq("Certificate Request",
3✔
2252
                                    msgs.at("certificate_request")[0],
2✔
2253
                                    strip_message_header(vars.get_opt_bin("Message_CertificateRequest")));
3✔
2254
                     result.test_eq("Certificate",
3✔
2255
                                    msgs.at("certificate")[0],
2✔
2256
                                    strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
2257
                     result.test_eq("CertificateVerify",
3✔
2258
                                    msgs.at("certificate_verify")[0],
2✔
2259
                                    strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
2260
                     result.test_eq("Finished",
3✔
2261
                                    msgs.at("finished")[0],
2✔
2262
                                    strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2263

2264
                     result.test_eq("Server's entire first flight",
2✔
2265
                                    ctx->pull_send_buffer(),
2✔
2266
                                    concat(vars.get_req_bin("Record_ServerHello"),
4✔
2267
                                           vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2268

2269
                     result.confirm("Not yet aware of client's cert chain", ctx->server.peer_cert_chain().empty());
2✔
2270
                     result.confirm("Server could now send application data", ctx->server.is_active());
2✔
2271
                     result.confirm("handshake is not yet complete",
1✔
2272
                                    !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2273
                  }),
1✔
2274

2275
            CHECK("Receive Client's second flight",
2276
                  [&](Test::Result& result) {
1✔
2277
                     result.require("ctx is available", ctx != nullptr);
1✔
2278
                     // This encrypted message contains the following messages:
2279
                     // * client's Certificate message
2280
                     // * client's Certificate_Verify message
2281
                     // * client's Finished message
2282
                     ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2283

2284
                     ctx->check_callback_invocations(result,
2✔
2285
                                                     "client finished received",
2286
                                                     {"tls_inspect_handshake_msg_certificate",
2287
                                                      "tls_inspect_handshake_msg_certificate_verify",
2288
                                                      "tls_inspect_handshake_msg_finished",
2289
                                                      "tls_examine_extensions_certificate",
2290
                                                      "tls_verify_cert_chain",
2291
                                                      "tls_verify_message",
2292
                                                      "tls_current_timestamp",
2293
                                                      "tls_session_established",
2294
                                                      "tls_session_activated"});
2295

2296
                     const auto cert_chain = ctx->server.peer_cert_chain();
1✔
2297
                     result.confirm("Received client's cert chain",
2✔
2298
                                    !cert_chain.empty() && cert_chain.front() == client_certificate());
2✔
2299

2300
                     result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2301
                     result.confirm("handshake is complete", ctx->server.is_handshake_complete());
2✔
2302
                  }),
1✔
2303

2304
            CHECK("Receive Client close_notify",
2305
                  [&](Test::Result& result) {
1✔
2306
                     result.require("ctx is available", ctx != nullptr);
1✔
2307
                     ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2308

2309
                     ctx->check_callback_invocations(
2✔
2310
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2311

2312
                     result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2313
                     result.confirm("connection is still active", ctx->server.is_active());
2✔
2314
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2315
                  }),
1✔
2316

2317
            CHECK("Expect Server close_notify",
2318
                  [&](Test::Result& result) {
1✔
2319
                     result.require("ctx is available", ctx != nullptr);
1✔
2320
                     ctx->server.close();
1✔
2321

2322
                     result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2323
                     result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2324
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2325
                     result.test_eq("Server's close notify",
2✔
2326
                                    ctx->pull_send_buffer(),
2✔
2327
                                    vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2328
                  }),
1✔
2329

2330
         };
6✔
2331
      }
2✔
2332

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

2336
         // 32 - for server hello random
2337
         // 32 - for KeyShare (eph. x25519 pair)
2338
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2339

2340
         std::unique_ptr<Server_Context> ctx;
1✔
2341

2342
         return {
1✔
2343
            CHECK("Receive Client Hello",
2344
                  [&](Test::Result& result) {
1✔
2345
                     ctx =
1✔
2346
                        std::make_unique<Server_Context>(std::move(rng),
1✔
2347
                                                         std::make_shared<RFC8448_Text_Policy>("rfc8448_compat_server"),
2✔
2348
                                                         vars.get_req_u64("CurrentTimestamp"),
1✔
2349
                                                         sort_rfc8448_extensions,
2350
                                                         make_mock_signatures(vars));
3✔
2351
                     result.confirm("server not closed", !ctx->server.is_closed());
2✔
2352

2353
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2354

2355
                     ctx->check_callback_invocations(result,
2✔
2356
                                                     "client hello received",
2357
                                                     {"tls_emit_data",
2358
                                                      "tls_examine_extensions_client_hello",
2359
                                                      "tls_modify_extensions_server_hello",
2360
                                                      "tls_modify_extensions_encrypted_extensions",
2361
                                                      "tls_modify_extensions_certificate",
2362
                                                      "tls_sign_message",
2363
                                                      "tls_generate_ephemeral_key",
2364
                                                      "tls_ephemeral_key_agreement",
2365
                                                      "tls_inspect_handshake_msg_client_hello",
2366
                                                      "tls_inspect_handshake_msg_server_hello",
2367
                                                      "tls_inspect_handshake_msg_encrypted_extensions",
2368
                                                      "tls_inspect_handshake_msg_certificate",
2369
                                                      "tls_inspect_handshake_msg_certificate_verify",
2370
                                                      "tls_inspect_handshake_msg_finished"});
2371
                  }),
1✔
2372

2373
            CHECK("Verify server's generated handshake messages",
2374
                  [&](Test::Result& result) {
1✔
2375
                     result.require("ctx is available", ctx != nullptr);
1✔
2376
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
2377

2378
                     result.test_eq("Server Hello",
3✔
2379
                                    msgs.at("server_hello")[0],
2✔
2380
                                    strip_message_header(vars.get_opt_bin("Message_ServerHello")));
3✔
2381
                     result.test_eq("Encrypted Extensions",
3✔
2382
                                    msgs.at("encrypted_extensions")[0],
2✔
2383
                                    strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2384
                     result.test_eq("Certificate",
3✔
2385
                                    msgs.at("certificate")[0],
2✔
2386
                                    strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
2387
                     result.test_eq("CertificateVerify",
3✔
2388
                                    msgs.at("certificate_verify")[0],
2✔
2389
                                    strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
2390
                     result.test_eq("Finished",
3✔
2391
                                    msgs.at("finished")[0],
2✔
2392
                                    strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2393

2394
                     // Those records contain the required Change Cipher Spec message the server must produce for compatibility mode compliance
2395
                     result.test_eq("Server's entire first flight",
2✔
2396
                                    ctx->pull_send_buffer(),
2✔
2397
                                    concat(vars.get_req_bin("Record_ServerHello"),
4✔
2398
                                           vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2399

2400
                     result.confirm("Server could now send application data", ctx->server.is_active());
2✔
2401
                     result.confirm("handshake is not yet complete",
1✔
2402
                                    !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2403
                  }),
1✔
2404

2405
            CHECK("Receive Client Finished",
2406
                  [&](Test::Result& result) {
1✔
2407
                     result.require("ctx is available", ctx != nullptr);
1✔
2408
                     ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2409

2410
                     ctx->check_callback_invocations(result,
2✔
2411
                                                     "client finished received",
2412
                                                     {"tls_inspect_handshake_msg_finished",
2413
                                                      "tls_current_timestamp",
2414
                                                      "tls_session_established",
2415
                                                      "tls_session_activated"});
2416

2417
                     result.confirm("TLS handshake fully finished", ctx->server.is_active());
2✔
2418
                     result.confirm("handshake is complete", ctx->server.is_handshake_complete());
2✔
2419
                  }),
1✔
2420

2421
            CHECK("Receive Client close_notify",
2422
                  [&](Test::Result& result) {
1✔
2423
                     result.require("ctx is available", ctx != nullptr);
1✔
2424
                     ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2425

2426
                     ctx->check_callback_invocations(
2✔
2427
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2428

2429
                     result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2430
                     result.confirm("connection is still active", ctx->server.is_active());
2✔
2431
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2432
                  }),
1✔
2433

2434
            CHECK("Expect Server close_notify",
2435
                  [&](Test::Result& result) {
1✔
2436
                     result.require("ctx is available", ctx != nullptr);
1✔
2437
                     ctx->server.close();
1✔
2438

2439
                     result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2440
                     result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2441
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2442
                     result.test_eq("Server's close notify",
2✔
2443
                                    ctx->pull_send_buffer(),
2✔
2444
                                    vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2445
                  }),
1✔
2446

2447
         };
6✔
2448
      }
2✔
2449

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

2453
         // 32 - for server hello random
2454
         // 32 - for KeyShare (eph. x25519 key pair)
2455
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2456

2457
         std::unique_ptr<Server_Context> ctx;
1✔
2458

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

2485
                     ctx = std::make_unique<Server_Context>(
1✔
2486
                        std::move(rng),
2487
                        std::make_shared<RFC8448_Text_Policy>("rfc8448_psk_dhe", false /* no rfc8448 */),
2✔
2488
                        vars.get_req_u64("CurrentTimestamp"),
1✔
2489
                        sort_our_extensions,
2490
                        make_mock_signatures(vars),
1✔
2491
                        false,
1✔
2492
                        std::nullopt,
2493
                        ExternalPSK(vars.get_req_str("PskIdentity"),
2✔
2494
                                    vars.get_req_str("PskPRF"),
2✔
2495
                                    lock(vars.get_req_bin("PskSecret"))));
5✔
2496
                     result.confirm("server not closed", !ctx->server.is_closed());
2✔
2497

2498
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2499

2500
                     ctx->check_callback_invocations(result,
2✔
2501
                                                     "client hello received",
2502
                                                     {"tls_emit_data",
2503
                                                      "tls_examine_extensions_client_hello",
2504
                                                      "tls_modify_extensions_server_hello",
2505
                                                      "tls_modify_extensions_encrypted_extensions",
2506
                                                      "tls_generate_ephemeral_key",
2507
                                                      "tls_ephemeral_key_agreement",
2508
                                                      "tls_inspect_handshake_msg_client_hello",
2509
                                                      "tls_inspect_handshake_msg_server_hello",
2510
                                                      "tls_inspect_handshake_msg_encrypted_extensions",
2511
                                                      "tls_inspect_handshake_msg_finished"});
2512
                  }),
1✔
2513

2514
            CHECK("Verify generated messages in server's first flight",
2515
                  [&](Test::Result& result) {
1✔
2516
                     result.require("ctx is available", ctx != nullptr);
1✔
2517
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
2518

2519
                     result.test_eq("Server Hello",
3✔
2520
                                    msgs.at("server_hello")[0],
2✔
2521
                                    strip_message_header(vars.get_opt_bin("Message_ServerHello")));
3✔
2522
                     result.test_eq("Encrypted Extensions",
3✔
2523
                                    msgs.at("encrypted_extensions")[0],
2✔
2524
                                    strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2525
                     result.test_eq("Server Finished",
3✔
2526
                                    msgs.at("finished")[0],
2✔
2527
                                    strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2528

2529
                     result.test_eq("Server's entire first flight",
2✔
2530
                                    ctx->pull_send_buffer(),
2✔
2531
                                    concat(vars.get_req_bin("Record_ServerHello"),
4✔
2532
                                           vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2533

2534
                     result.confirm("Server can now send application data", ctx->server.is_active());
2✔
2535
                     result.confirm("handshake is not yet complete",
1✔
2536
                                    !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2537
                  }),
1✔
2538

2539
            CHECK("Send Client Finished",
2540
                  [&](Test::Result& result) {
1✔
2541
                     result.require("ctx is available", ctx != nullptr);
1✔
2542
                     ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2543
                     result.require("PSK negotiated",
2✔
2544
                                    ctx->psk_identity_negotiated() == vars.get_req_str("PskIdentity"));
2✔
2545

2546
                     ctx->check_callback_invocations(result,
2✔
2547
                                                     "client finished received",
2548
                                                     {"tls_inspect_handshake_msg_finished",
2549
                                                      "tls_current_timestamp",
2550
                                                      "tls_session_established",
2551
                                                      "tls_session_activated"});
2552
                  }),
1✔
2553

2554
            CHECK("Exchange Application Data",
2555
                  [&](Test::Result& result) {
1✔
2556
                     result.require("ctx is available", ctx != nullptr);
1✔
2557
                     ctx->server.received_data(vars.get_req_bin("Record_Client_AppData"));
2✔
2558
                     ctx->check_callback_invocations(result, "application data received", {"tls_record_received"});
2✔
2559

2560
                     const auto rcvd = ctx->pull_receive_buffer();
1✔
2561
                     result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Client_AppData"));
3✔
2562
                     result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
1✔
2563

2564
                     ctx->send(vars.get_req_bin("Server_AppData"));
3✔
2565
                     ctx->check_callback_invocations(result, "application data sent", {"tls_emit_data"});
2✔
2566
                     result.test_eq("correct server application data",
2✔
2567
                                    ctx->pull_send_buffer(),
2✔
2568
                                    vars.get_req_bin("Record_Server_AppData"));
2✔
2569
                  }),
1✔
2570

2571
            CHECK("Terminate Connection",
2572
                  [&](Test::Result& result) {
1✔
2573
                     result.require("ctx is available", ctx != nullptr);
1✔
2574
                     ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2575

2576
                     ctx->check_callback_invocations(
2✔
2577
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2578

2579
                     result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2580
                     result.confirm("connection is still active", ctx->server.is_active());
2✔
2581
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2582

2583
                     ctx->server.close();
1✔
2584

2585
                     result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2586
                     result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2587
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2588
                     result.test_eq("Server's close notify",
2✔
2589
                                    ctx->pull_send_buffer(),
2✔
2590
                                    vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2591
                  }),
1✔
2592
         };
6✔
2593
      }
2✔
2594

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

2598
         // 32 - for server hello random
2599
         // 32 - for KeyShare (eph. x25519 key pair)
2600
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2601

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

2626
         std::unique_ptr<Server_Context> ctx;
1✔
2627

2628
         return {
1✔
2629
            CHECK("Receive Client Hello",
2630
                  [&](Test::Result& result) {
1✔
2631
                     ctx = std::make_unique<Server_Context>(std::move(rng),
1✔
2632
                                                            std::make_shared<RFC8448_Text_Policy>("rfc8448_rawpubkey"),
2✔
2633
                                                            vars.get_req_u64("CurrentTimestamp"),
1✔
2634
                                                            sort_our_extensions,
2635
                                                            make_mock_signatures(vars));
3✔
2636
                     result.confirm("server not closed", !ctx->server.is_closed());
2✔
2637

2638
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2639

2640
                     ctx->check_callback_invocations(result,
2✔
2641
                                                     "client hello received",
2642
                                                     {"tls_emit_data",
2643
                                                      "tls_examine_extensions_client_hello",
2644
                                                      "tls_modify_extensions_server_hello",
2645
                                                      "tls_modify_extensions_encrypted_extensions",
2646
                                                      "tls_modify_extensions_certificate_request",
2647
                                                      "tls_modify_extensions_certificate",
2648
                                                      "tls_sign_message",
2649
                                                      "tls_generate_ephemeral_key",
2650
                                                      "tls_ephemeral_key_agreement",
2651
                                                      "tls_inspect_handshake_msg_client_hello",
2652
                                                      "tls_inspect_handshake_msg_server_hello",
2653
                                                      "tls_inspect_handshake_msg_encrypted_extensions",
2654
                                                      "tls_inspect_handshake_msg_certificate_request",
2655
                                                      "tls_inspect_handshake_msg_certificate",
2656
                                                      "tls_inspect_handshake_msg_certificate_verify",
2657
                                                      "tls_inspect_handshake_msg_finished"});
2658
                  }),
1✔
2659

2660
            CHECK("Verify server's generated handshake messages",
2661
                  [&](Test::Result& result) {
1✔
2662
                     result.require("ctx is available", ctx != nullptr);
1✔
2663
                     const auto& msgs = ctx->observed_handshake_messages();
1✔
2664

2665
                     result.test_eq("Server Hello",
3✔
2666
                                    msgs.at("server_hello")[0],
2✔
2667
                                    strip_message_header(vars.get_opt_bin("Message_ServerHello")));
3✔
2668
                     result.test_eq("Encrypted Extensions",
3✔
2669
                                    msgs.at("encrypted_extensions")[0],
2✔
2670
                                    strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2671
                     result.test_eq("Certificate Request",
3✔
2672
                                    msgs.at("certificate_request")[0],
2✔
2673
                                    strip_message_header(vars.get_opt_bin("Message_CertificateRequest")));
3✔
2674
                     result.test_eq("Certificate",
3✔
2675
                                    msgs.at("certificate")[0],
2✔
2676
                                    strip_message_header(vars.get_opt_bin("Message_Server_Certificate")));
3✔
2677
                     result.test_eq("CertificateVerify",
3✔
2678
                                    msgs.at("certificate_verify")[0],
2✔
2679
                                    strip_message_header(vars.get_opt_bin("Message_Server_CertificateVerify")));
3✔
2680
                     result.test_eq("Finished",
3✔
2681
                                    msgs.at("finished")[0],
2✔
2682
                                    strip_message_header(vars.get_opt_bin("Message_Server_Finished")));
3✔
2683

2684
                     result.test_eq("Server's entire first flight",
2✔
2685
                                    ctx->pull_send_buffer(),
2✔
2686
                                    concat(vars.get_req_bin("Record_ServerHello"),
4✔
2687
                                           vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2688

2689
                     result.confirm("Not yet aware of client's cert chain", ctx->server.peer_cert_chain().empty());
2✔
2690
                     result.confirm("Server could now send application data", ctx->server.is_active());
2✔
2691
                     result.confirm("handshake is not yet complete",
1✔
2692
                                    !ctx->server.is_handshake_complete());  // See RFC 8446 4.4.4
1✔
2693
                  }),
1✔
2694

2695
            CHECK("Receive Client's second flight",
2696
                  [&](Test::Result& result) {
1✔
2697
                     result.require("ctx is available", ctx != nullptr);
1✔
2698
                     // This encrypted message contains the following messages:
2699
                     // * client's Certificate message
2700
                     // * client's Certificate_Verify message
2701
                     // * client's Finished message
2702
                     ctx->server.received_data(vars.get_req_bin("Record_ClientFinished"));
2✔
2703

2704
                     ctx->check_callback_invocations(result,
2✔
2705
                                                     "client finished received",
2706
                                                     {"tls_inspect_handshake_msg_certificate",
2707
                                                      "tls_inspect_handshake_msg_certificate_verify",
2708
                                                      "tls_inspect_handshake_msg_finished",
2709
                                                      "tls_examine_extensions_certificate",
2710
                                                      "tls_verify_raw_public_key",
2711
                                                      "tls_verify_message",
2712
                                                      "tls_current_timestamp",
2713
                                                      "tls_session_established",
2714
                                                      "tls_session_activated"});
2715

2716
                     const auto raw_pk = ctx->server.peer_raw_public_key();
1✔
2717
                     result.confirm(
2✔
2718
                        "Received client's raw public key",
2719
                        raw_pk && raw_pk->fingerprint_public() == client_raw_public_key_pair()->fingerprint_public());
5✔
2720

2721
                     result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2722
                     result.confirm("handshake is complete", ctx->server.is_handshake_complete());
2✔
2723
                  }),
1✔
2724

2725
            CHECK("Receive Client close_notify",
2726
                  [&](Test::Result& result) {
1✔
2727
                     result.require("ctx is available", ctx != nullptr);
1✔
2728
                     ctx->server.received_data(vars.get_req_bin("Record_Client_CloseNotify"));
2✔
2729

2730
                     ctx->check_callback_invocations(
2✔
2731
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2732

2733
                     result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2734
                     result.confirm("connection is still active", ctx->server.is_active());
2✔
2735
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2736
                  }),
1✔
2737

2738
            CHECK("Expect Server close_notify",
2739
                  [&](Test::Result& result) {
1✔
2740
                     result.require("ctx is available", ctx != nullptr);
1✔
2741
                     ctx->server.close();
1✔
2742

2743
                     result.confirm("connection is now inactive", !ctx->server.is_active());
2✔
2744
                     result.confirm("connection is now closed", ctx->server.is_closed());
2✔
2745
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2746
                     result.test_eq("Server's close notify",
2✔
2747
                                    ctx->pull_send_buffer(),
2✔
2748
                                    vars.get_req_bin("Record_Server_CloseNotify"));
2✔
2749
                  }),
1✔
2750
         };
6✔
2751
      }
2✔
2752
};
2753

2754
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_client", Test_TLS_RFC8448_Client);
2755
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_server", Test_TLS_RFC8448_Server);
2756

2757
#endif
2758

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