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

randombit / botan / 21943010187

12 Feb 2026 10:33AM UTC coverage: 90.061% (-0.006%) from 90.067%
21943010187

Pull #5318

github

web-flow
Merge 005a803db into f97d7db3f
Pull Request #5318: Allow disabling TLS 1.2 at Build Time

102245 of 113528 relevant lines covered (90.06%)

11733046.67 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_12) && defined(BOTAN_HAS_TLS_13) && defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) &&             \
17
   defined(BOTAN_HAS_AEAD_GCM) && defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_X25519) && defined(BOTAN_HAS_SHA2_32) && \
18
   defined(BOTAN_HAS_SHA2_64) && 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_12.h>
35
   #include <botan/tls_extensions_13.h>
36
   #include <botan/tls_messages.h>
37
   #include <botan/tls_policy.h>
38
   #include <botan/tls_server.h>
39
   #include <botan/tls_session_manager.h>
40
   #include <botan/x509_key.h>
41
   #include <botan/internal/fmt.h>
42
   #include <botan/internal/stl_util.h>
43
#endif
44

45
namespace Botan_Tests {
46

47
#if defined(BOTAN_CAN_RUN_TEST_TLS_RFC8448)
48

49
namespace {
50

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

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

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

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

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

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

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

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

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

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

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

112
   private:
113
      size_t m_padding_bytes;
114
};
115

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

427
         return m_server_private_key;
3✔
428
      }
429

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

541
   private:
542
      bool m_rfc8448;
543
};
544

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

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

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

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

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

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

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

591
         return handle;
1✔
592
      }
593

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

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

612
         return found_sessions;
7✔
613
      }
×
614

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

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

623
   private:
624
      std::vector<Session_with_Handle> m_sessions;
625
};
626

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

655
   public:
656
      virtual ~TLS_Context() = default;
70✔
657

658
      TLS_Context(TLS_Context&) = delete;
659
      TLS_Context& operator=(const TLS_Context&) = delete;
660

661
      TLS_Context(TLS_Context&&) = delete;
662
      TLS_Context& operator=(TLS_Context&&) = delete;
663

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

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

668
      uint64_t last_received_seq_no() const { return m_callbacks->last_received_seq_no(); }
4✔
669

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

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

693
         m_callbacks->reset_callback_invocation_counters();
60✔
694
      }
60✔
695

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

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

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

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

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

709
   protected:
710
      std::shared_ptr<Test_TLS_13_Callbacks> m_callbacks;  // NOLINT(*-non-private-member-variable*)
711
      std::shared_ptr<Test_Credentials> m_creds;           // NOLINT(*-non-private-member-variable*)
712

713
      std::shared_ptr<Botan::RandomNumberGenerator> m_rng;     // NOLINT(*-non-private-member-variable*)
714
      std::shared_ptr<RFC8448_Session_Manager> m_session_mgr;  // NOLINT(*-non-private-member-variable*)
715
      std::shared_ptr<const RFC8448_Text_Policy> m_policy;     // NOLINT(*-non-private-member-variable*)
716
};
717

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

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

745
      Botan::TLS::Client client;  // NOLINT(*-non-private-member-variable*)
746
};
747

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

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

770
      Botan::TLS::Server server;  // NOLINT(*-non-private-member-variable*)
771
};
772

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

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

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

827
void add_early_data_indication(Botan::TLS::Extensions& exts) {
1✔
828
   exts.add(new Botan::TLS::EarlyDataIndication());  // NOLINT(*-owning-memory)
1✔
829
}
1✔
830

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

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

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

845
   mock("Server_MessageToSign", "Server_MessageSignature");
18✔
846
   mock("Client_MessageToSign", "Client_MessageSignature");
18✔
847

848
   return result;
9✔
849
}
×
850

851
}  // namespace
852

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

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

902
      virtual std::string side() const = 0;
903

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

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

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

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

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

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

988
               add_renegotiation_extension(exts);
1✔
989
               sort_rfc8448_extensions(exts, side);
1✔
990
            }
991
         };
1✔
992

993
         std::unique_ptr<Client_Context> ctx;
1✔
994

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

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

1014
                     result.test_eq(
2✔
1015
                        "TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
3✔
1016
                  }),
1✔
1017

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1134
         // 32 - for client hello random
1135
         // 32 - for KeyShare (eph. x25519 key pair)
1136
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1137

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

1144
               add_renegotiation_extension(exts);
1✔
1145

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

1155
         std::unique_ptr<Client_Context> ctx;
1✔
1156

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

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

1179
                     result.test_eq(
2✔
1180
                        "TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
3✔
1181
                  })
1✔
1182

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

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

1196
               if(flights == 1) {
2✔
1197
                  add_renegotiation_extension(exts);
1✔
1198
               }
1199

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

1206
               sort_rfc8448_extensions(exts, side);
2✔
1207
            }
1208
         };
2✔
1209

1210
         // Fallback RNG is required to for blinding in ECDH with P-256
1211
         auto& fallback_rng = this->rng();
1✔
1212
         auto rng = std::make_unique<Fixed_Output_RNG>(fallback_rng);
1✔
1213

1214
         // 32 - client hello random
1215
         // 32 - eph. x25519 key pair
1216
         // 32 - eph. P-256 key pair
1217
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1218

1219
         std::unique_ptr<Client_Context> ctx;
1✔
1220

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

1230
                     ctx->check_callback_invocations(result,
2✔
1231
                                                     "client hello prepared",
1232
                                                     {
1233
                                                        "tls_emit_data",
1234
                                                        "tls_inspect_handshake_msg_client_hello",
1235
                                                        "tls_modify_extensions_client_hello",
1236
                                                        "tls_generate_ephemeral_key",
1237
                                                        "tls_current_timestamp",
1238
                                                     });
1239

1240
                     result.test_eq(
2✔
1241
                        "TLS client hello (1)", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
3✔
1242
                  }),
1✔
1243

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

1249
                     ctx->check_callback_invocations(result,
2✔
1250
                                                     "hello retry request received",
1251
                                                     {
1252
                                                        "tls_emit_data",
1253
                                                        "tls_inspect_handshake_msg_hello_retry_request",
1254
                                                        "tls_examine_extensions_hello_retry_request",
1255
                                                        "tls_inspect_handshake_msg_client_hello",
1256
                                                        "tls_modify_extensions_client_hello",
1257
                                                        "tls_generate_ephemeral_key",
1258
                                                     });
1259

1260
                     result.test_eq(
2✔
1261
                        "TLS client hello (2)", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_2"));
3✔
1262
                  }),
1✔
1263

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

1269
                     ctx->check_callback_invocations(result,
2✔
1270
                                                     "server hello received",
1271
                                                     {
1272
                                                        "tls_inspect_handshake_msg_server_hello",
1273
                                                        "tls_examine_extensions_server_hello",
1274
                                                        "tls_ephemeral_key_agreement",
1275
                                                     });
1276
                  }),
1✔
1277

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

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

1298
                     result.test_eq(
2✔
1299
                        "client finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
3✔
1300
                  }),
1✔
1301

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

1311
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1312
                     ctx->check_callback_invocations(
2✔
1313
                        result, "encrypted handshake messages received", {"tls_alert", "tls_peer_closed_connection"});
1314

1315
                     result.confirm("connection is closed", ctx->client.is_closed());
2✔
1316
                  }),
1✔
1317
         };
6✔
1318
      }
2✔
1319

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

1323
         // 32 - for client hello random
1324
         // 32 - for eph. x25519 key pair
1325
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1326

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

1336
         std::unique_ptr<Client_Context> ctx;
1✔
1337

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

1349
                     ctx->check_callback_invocations(result,
2✔
1350
                                                     "initial callbacks",
1351
                                                     {
1352
                                                        "tls_emit_data",
1353
                                                        "tls_inspect_handshake_msg_client_hello",
1354
                                                        "tls_modify_extensions_client_hello",
1355
                                                        "tls_generate_ephemeral_key",
1356
                                                        "tls_current_timestamp",
1357
                                                     });
1358

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

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

1367
                     ctx->check_callback_invocations(result,
2✔
1368
                                                     "callbacks after server hello",
1369
                                                     {
1370
                                                        "tls_examine_extensions_server_hello",
1371
                                                        "tls_inspect_handshake_msg_server_hello",
1372
                                                        "tls_ephemeral_key_agreement",
1373
                                                     });
1374
                  }),
1✔
1375

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

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

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

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

1415
                     ctx->check_callback_invocations(result,
2✔
1416
                                                     "after sending close notify",
1417
                                                     {
1418
                                                        "tls_emit_data",
1419
                                                     });
1420

1421
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1422
                     result.confirm("connection closed", ctx->client.is_closed());
2✔
1423

1424
                     ctx->check_callback_invocations(
2✔
1425
                        result, "after receiving close notify", {"tls_alert", "tls_peer_closed_connection"});
1426
                  }),
1✔
1427
         };
5✔
1428
      }
2✔
1429

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

1433
         // 32 - client hello random
1434
         // 32 - legacy session ID
1435
         // 32 - eph. x25519 key pair
1436
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1437

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

1447
         std::unique_ptr<Client_Context> ctx;
1✔
1448

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

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

1460
                     ctx->check_callback_invocations(result,
2✔
1461
                                                     "client hello prepared",
1462
                                                     {
1463
                                                        "tls_emit_data",
1464
                                                        "tls_inspect_handshake_msg_client_hello",
1465
                                                        "tls_modify_extensions_client_hello",
1466
                                                        "tls_generate_ephemeral_key",
1467
                                                        "tls_current_timestamp",
1468
                                                     });
1469
                  }),
1✔
1470

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

1479
                     ctx->check_callback_invocations(result,
2✔
1480
                                                     "callbacks after server's first flight",
1481
                                                     {
1482
                                                        "tls_inspect_handshake_msg_server_hello",
1483
                                                        "tls_inspect_handshake_msg_encrypted_extensions",
1484
                                                        "tls_inspect_handshake_msg_certificate",
1485
                                                        "tls_inspect_handshake_msg_certificate_verify",
1486
                                                        "tls_inspect_handshake_msg_finished",
1487
                                                        "tls_examine_extensions_server_hello",
1488
                                                        "tls_examine_extensions_encrypted_extensions",
1489
                                                        "tls_examine_extensions_certificate",
1490
                                                        "tls_emit_data",
1491
                                                        "tls_current_timestamp",
1492
                                                        "tls_session_established",
1493
                                                        "tls_session_activated",
1494
                                                        "tls_verify_cert_chain",
1495
                                                        "tls_verify_message",
1496
                                                        "tls_ephemeral_key_agreement",
1497
                                                     });
1498

1499
                     result.test_eq("CCS + Client Finished",
2✔
1500
                                    ctx->pull_send_buffer(),
2✔
1501
                                    // ClientFinished contains the expected ChangeCipherSpec record
1502
                                    vars.get_req_bin("Record_ClientFinished"));
2✔
1503

1504
                     result.confirm("client is ready to send application traffic", ctx->client.is_active());
2✔
1505
                     result.confirm("handshake is complete", ctx->client.is_handshake_complete());
2✔
1506
                  }),
1✔
1507

1508
            CHECK("Close connection",
1509
                  [&](Test::Result& result) {
1✔
1510
                     result.require("ctx is available", ctx != nullptr);
1✔
1511
                     ctx->client.close();
1✔
1512

1513
                     result.test_eq(
2✔
1514
                        "Client close_notify", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1515

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

1520
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1521

1522
                     result.confirm("client connection was terminated", ctx->client.is_closed());
2✔
1523
                  }),
1✔
1524
         };
4✔
1525
      }
2✔
1526

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

1530
         // 32 - for client hello random
1531
         // 32 - for KeyShare (eph. x25519 key pair)
1532
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1533

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

1553
         std::unique_ptr<Client_Context> ctx;
1✔
1554

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

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

1579
                     result.test_eq(
2✔
1580
                        "TLS client hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
3✔
1581
                  }),
1✔
1582

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

1594
                     result.confirm("client is not yet active", !ctx->client.is_active());
2✔
1595
                     result.confirm("handshake is not yet complete", !ctx->client.is_handshake_complete());
2✔
1596
                  }),
1✔
1597

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

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

1617
                  result.test_eq(
2✔
1618
                     "correct handshake finished", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientFinished"));
3✔
1619
               }),
1✔
1620

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

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

1628
                     result.test_eq("correct client application data",
2✔
1629
                                    ctx->pull_send_buffer(),
2✔
1630
                                    vars.get_req_bin("Record_Client_AppData"));
2✔
1631
                  }),
1✔
1632

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

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

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

1645
            CHECK("Close Connection",
1646
                  [&](Test::Result& result) {
1✔
1647
                     result.require("ctx is available", ctx != nullptr);
1✔
1648
                     ctx->client.close();
1✔
1649

1650
                     result.test_eq(
2✔
1651
                        "close payload", ctx->pull_send_buffer(), vars.get_req_bin("Record_Client_CloseNotify"));
3✔
1652
                     ctx->check_callback_invocations(result, "CLOSE_NOTIFY sent", {"tls_emit_data"});
2✔
1653

1654
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1655
                     ctx->check_callback_invocations(
2✔
1656
                        result, "CLOSE_NOTIFY received", {"tls_alert", "tls_peer_closed_connection"});
1657

1658
                     result.confirm("connection is closed", ctx->client.is_closed());
2✔
1659
                  }),
1✔
1660
         };
7✔
1661
      }
2✔
1662

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

1666
         // 32 - for client hello random
1667
         // 32 - for KeyShare (eph. x25519 key pair)
1668
         add_entropy(*rng, vars.get_req_bin("Client_RNG_Pool"));
2✔
1669

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

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

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

1704
                     ctx->check_callback_invocations(result,
2✔
1705
                                                     "initial callbacks",
1706
                                                     {
1707
                                                        "tls_emit_data",
1708
                                                        "tls_inspect_handshake_msg_client_hello",
1709
                                                        "tls_modify_extensions_client_hello",
1710
                                                        "tls_generate_ephemeral_key",
1711
                                                        "tls_current_timestamp",
1712
                                                     });
1713

1714
                     result.test_eq("Client Hello", ctx->pull_send_buffer(), vars.get_req_bin("Record_ClientHello_1"));
4✔
1715
                  }),
1✔
1716

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

1722
                     ctx->check_callback_invocations(result,
2✔
1723
                                                     "callbacks after server hello",
1724
                                                     {
1725
                                                        "tls_examine_extensions_server_hello",
1726
                                                        "tls_inspect_handshake_msg_server_hello",
1727
                                                        "tls_ephemeral_key_agreement",
1728
                                                     });
1729
                  }),
1✔
1730

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

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

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

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

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

1775
                     ctx->check_callback_invocations(result,
2✔
1776
                                                     "after sending close notify",
1777
                                                     {
1778
                                                        "tls_emit_data",
1779
                                                     });
1780

1781
                     ctx->client.received_data(vars.get_req_bin("Record_Server_CloseNotify"));
2✔
1782
                     result.confirm("connection closed", ctx->client.is_closed());
2✔
1783

1784
                     ctx->check_callback_invocations(
2✔
1785
                        result, "after receiving close notify", {"tls_alert", "tls_peer_closed_connection"});
1786
                  }),
1✔
1787
         };
5✔
1788
      }
2✔
1789
};
1790

1791
class Test_TLS_RFC8448_Server : public Test_TLS_RFC8448 {
1✔
1792
   private:
1793
      std::string side() const override { return "Server"; }
7✔
1794

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

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

1803
         std::unique_ptr<Server_Context> ctx;
1✔
1804

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

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

1828
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
1829

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

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

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

1866
                     result.test_eq("Server's entire first flight",
2✔
1867
                                    ctx->pull_send_buffer(),
2✔
1868
                                    concat(vars.get_req_bin("Record_ServerHello"),
4✔
1869
                                           vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
1870

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

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

1885
                     ctx->check_callback_invocations(result,
2✔
1886
                                                     "client finished received",
1887
                                                     {"tls_inspect_handshake_msg_finished",
1888
                                                      "tls_current_timestamp",
1889
                                                      "tls_session_established",
1890
                                                      "tls_session_activated"});
1891
                  }),
1✔
1892

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

1898
                     result.test_eq("session ticket was sent", new_tickets, 1);
1✔
1899

1900
                     ctx->check_callback_invocations(result,
2✔
1901
                                                     "issued new session ticket",
1902
                                                     {"tls_inspect_handshake_msg_new_session_ticket",
1903
                                                      "tls_current_timestamp",
1904
                                                      "tls_emit_data",
1905
                                                      "tls_modify_extensions_new_session_ticket",
1906
                                                      "tls_should_persist_resumption_information"});
1907
                  }),
1✔
1908

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

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

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

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

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

1934
                     result.test_eq("correct server application data",
2✔
1935
                                    ctx->pull_send_buffer(),
2✔
1936
                                    vars.get_req_bin("Record_Server_AppData"));
2✔
1937
                  }),
1✔
1938

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

1944
                     ctx->check_callback_invocations(
2✔
1945
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
1946

1947
                     result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
1948
                     result.confirm("connection is still active", ctx->server.is_active());
2✔
1949
                     result.confirm("handshake is still finished", ctx->server.is_handshake_complete());
2✔
1950
                  }),
1✔
1951

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

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

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

1970
         // 32 - for server hello random
1971
         // 32 - for KeyShare (eph. x25519 key pair)
1972
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
1973

1974
         std::unique_ptr<Server_Context> ctx;
1✔
1975

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

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

1999
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2000

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

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

2023
                     result.test_eq("Server Hello",
3✔
2024
                                    msgs.at("server_hello")[0],
2✔
2025
                                    strip_message_header(vars.get_opt_bin("Message_ServerHello")));
3✔
2026
                     result.test_eq("Encrypted Extensions",
3✔
2027
                                    msgs.at("encrypted_extensions")[0],
2✔
2028
                                    strip_message_header(vars.get_opt_bin("Message_EncryptedExtensions")));
3✔
2029

2030
                     result.test_eq("Server's entire first flight",
2✔
2031
                                    ctx->pull_send_buffer(),
2✔
2032
                                    concat(vars.get_req_bin("Record_ServerHello"),
4✔
2033
                                           vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2034

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

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

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

2055
         // 32 - for server hello random
2056
         // 32 - for KeyShare (eph. P-256 key pair)
2057
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2058

2059
         std::unique_ptr<Server_Context> ctx;
1✔
2060

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

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

2082
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2083

2084
                     ctx->check_callback_invocations(result,
2✔
2085
                                                     "client hello received",
2086
                                                     {"tls_emit_data",
2087
                                                      "tls_examine_extensions_client_hello",
2088
                                                      "tls_modify_extensions_hello_retry_request",
2089
                                                      "tls_inspect_handshake_msg_client_hello",
2090
                                                      "tls_inspect_handshake_msg_hello_retry_request"});
2091
                  }),
1✔
2092

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

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

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

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

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

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

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

2161
                     ctx->check_callback_invocations(result,
2✔
2162
                                                     "client finished received",
2163
                                                     {"tls_inspect_handshake_msg_finished",
2164
                                                      "tls_current_timestamp",
2165
                                                      "tls_session_established",
2166
                                                      "tls_session_activated"});
2167

2168
                     result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2169
                     result.confirm("handshake is complete", ctx->server.is_handshake_complete());
2✔
2170
                  }),
1✔
2171

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

2177
                     ctx->check_callback_invocations(
2✔
2178
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2179

2180
                     result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2181
                     result.confirm("connection is still active", ctx->server.is_active());
2✔
2182
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2183
                  }),
1✔
2184

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

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

2198
         };
8✔
2199
      }
2✔
2200

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

2204
         // 32 - for server hello random
2205
         // 32 - for KeyShare (eph. x25519 pair)
2206
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2207

2208
         std::unique_ptr<Server_Context> ctx;
1✔
2209

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

2222
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2223

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

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

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

2268
                     result.test_eq("Server's entire first flight",
2✔
2269
                                    ctx->pull_send_buffer(),
2✔
2270
                                    concat(vars.get_req_bin("Record_ServerHello"),
4✔
2271
                                           vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2272

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

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

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

2300
                     const auto cert_chain = ctx->server.peer_cert_chain();
1✔
2301
                     result.confirm("Received client's cert chain",
2✔
2302
                                    !cert_chain.empty() && cert_chain.front() == client_certificate());
2✔
2303

2304
                     result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2305
                     result.confirm("handshake is complete", ctx->server.is_handshake_complete());
2✔
2306
                  }),
1✔
2307

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

2313
                     ctx->check_callback_invocations(
2✔
2314
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2315

2316
                     result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2317
                     result.confirm("connection is still active", ctx->server.is_active());
2✔
2318
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2319
                  }),
1✔
2320

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

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

2334
         };
6✔
2335
      }
2✔
2336

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

2340
         // 32 - for server hello random
2341
         // 32 - for KeyShare (eph. x25519 pair)
2342
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2343

2344
         std::unique_ptr<Server_Context> ctx;
1✔
2345

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

2357
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2358

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

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

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

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

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

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

2414
                     ctx->check_callback_invocations(result,
2✔
2415
                                                     "client finished received",
2416
                                                     {"tls_inspect_handshake_msg_finished",
2417
                                                      "tls_current_timestamp",
2418
                                                      "tls_session_established",
2419
                                                      "tls_session_activated"});
2420

2421
                     result.confirm("TLS handshake fully finished", ctx->server.is_active());
2✔
2422
                     result.confirm("handshake is complete", ctx->server.is_handshake_complete());
2✔
2423
                  }),
1✔
2424

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

2430
                     ctx->check_callback_invocations(
2✔
2431
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2432

2433
                     result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2434
                     result.confirm("connection is still active", ctx->server.is_active());
2✔
2435
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2436
                  }),
1✔
2437

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

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

2451
         };
6✔
2452
      }
2✔
2453

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

2457
         // 32 - for server hello random
2458
         // 32 - for KeyShare (eph. x25519 key pair)
2459
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2460

2461
         std::unique_ptr<Server_Context> ctx;
1✔
2462

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

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

2502
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2503

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

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

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

2533
                     result.test_eq("Server's entire first flight",
2✔
2534
                                    ctx->pull_send_buffer(),
2✔
2535
                                    concat(vars.get_req_bin("Record_ServerHello"),
4✔
2536
                                           vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2537

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

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

2550
                     ctx->check_callback_invocations(result,
2✔
2551
                                                     "client finished received",
2552
                                                     {"tls_inspect_handshake_msg_finished",
2553
                                                      "tls_current_timestamp",
2554
                                                      "tls_session_established",
2555
                                                      "tls_session_activated"});
2556
                  }),
1✔
2557

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

2564
                     const auto rcvd = ctx->pull_receive_buffer();
1✔
2565
                     result.test_eq("decrypted application traffic", rcvd, vars.get_req_bin("Client_AppData"));
3✔
2566
                     result.test_is_eq("sequence number", ctx->last_received_seq_no(), uint64_t(0));
1✔
2567

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

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

2580
                     ctx->check_callback_invocations(
2✔
2581
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2582

2583
                     result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2584
                     result.confirm("connection is still active", ctx->server.is_active());
2✔
2585
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2586

2587
                     ctx->server.close();
1✔
2588

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

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

2602
         // 32 - for server hello random
2603
         // 32 - for KeyShare (eph. x25519 key pair)
2604
         add_entropy(*rng, vars.get_req_bin("Server_RNG_Pool"));
2✔
2605

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

2630
         std::unique_ptr<Server_Context> ctx;
1✔
2631

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

2642
                     ctx->server.received_data(vars.get_req_bin("Record_ClientHello_1"));
2✔
2643

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

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

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

2688
                     result.test_eq("Server's entire first flight",
2✔
2689
                                    ctx->pull_send_buffer(),
2✔
2690
                                    concat(vars.get_req_bin("Record_ServerHello"),
4✔
2691
                                           vars.get_req_bin("Record_ServerHandshakeMessages")));
2✔
2692

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

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

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

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

2725
                     result.confirm("TLS handshake finished", ctx->server.is_active());
2✔
2726
                     result.confirm("handshake is complete", ctx->server.is_handshake_complete());
2✔
2727
                  }),
1✔
2728

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

2734
                     ctx->check_callback_invocations(
2✔
2735
                        result, "client finished received", {"tls_alert", "tls_peer_closed_connection"});
2736

2737
                     result.confirm("connection is not yet closed", !ctx->server.is_closed());
2✔
2738
                     result.confirm("connection is still active", ctx->server.is_active());
2✔
2739
                     result.confirm("handshake is still complete", ctx->server.is_handshake_complete());
2✔
2740
                  }),
1✔
2741

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

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

2758
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_client", Test_TLS_RFC8448_Client);
2759
BOTAN_REGISTER_TEST("tls", "tls_rfc8448_server", Test_TLS_RFC8448_Server);
2760

2761
#endif
2762

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