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

randombit / botan / 11844561993

14 Nov 2024 07:58PM UTC coverage: 91.178% (+0.1%) from 91.072%
11844561993

Pull #4435

github

web-flow
Merge 81dcb29da into e430f157a
Pull Request #4435: Test duration values ​​are now presented in seconds with six digits of precision. Tests without time measurements have been edited.

91856 of 100744 relevant lines covered (91.18%)

9311006.71 hits per line

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

93.87
/src/tests/unit_tls.cpp
1
/*
2
* (C) 2014,2015,2018 Jack Lloyd
3
*     2016 Matthias Gierlings
4
*     2017 René Korthaus, Rohde & Schwarz Cybersecurity
5
*     2017 Harry Reimann, Rohde & Schwarz Cybersecurity
6
*     2023 René Meusel, Rohde & Schwarz Cybersecurity
7
*
8
* Botan is released under the Simplified BSD License (see license.txt)
9
*/
10

11
#include "tests.h"
12
#include <memory>
13
#include <vector>
14

15
#if defined(BOTAN_HAS_TLS)
16

17
   #include <botan/tls_client.h>
18
   #include <botan/tls_exceptn.h>
19
   #include <botan/tls_extensions.h>
20
   #include <botan/tls_policy.h>
21
   #include <botan/tls_server.h>
22
   #include <botan/tls_session_manager_memory.h>
23
   #include <botan/tls_session_manager_noop.h>
24
   #include <botan/internal/tls_reader.h>
25

26
   #include <botan/ec_group.h>
27
   #include <botan/ecdh.h>
28
   #include <botan/ecdsa.h>
29
   #include <botan/hex.h>
30
   #include <botan/pkcs10.h>
31
   #include <botan/rsa.h>
32
   #include <botan/x509_ca.h>
33
   #include <botan/x509self.h>
34

35
   #if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
36
      #include <botan/tls_session_manager_sqlite.h>
37
   #endif
38

39
namespace Botan::TLS {
40

41
// TODO: remove this, once TLS 1.3 is fully implemented
42
class Strict_Policy_Without_TLS13 : public Strict_Policy {
1✔
43
      bool allow_tls13() const override { return false; }
4✔
44
};
45

46
}  // namespace Botan::TLS
47

48
#endif
49

50
namespace Botan_Tests {
51

52
namespace {
53

54
#if defined(BOTAN_HAS_TLS)
55
class Credentials_Manager_Test final : public Botan::Credentials_Manager {
56
   public:
57
      Credentials_Manager_Test(bool with_client_certs,
2✔
58
                               const Botan::X509_Certificate& rsa_cert,
59
                               Botan::Private_Key* rsa_key,
60
                               const Botan::X509_Certificate& rsa_ca,
61
                               const Botan::X509_CRL& rsa_crl,
62
                               const Botan::X509_Certificate& ecdsa_cert,
63
                               Botan::Private_Key* ecdsa_key,
64
                               const Botan::X509_Certificate& ecdsa_ca,
65
                               const Botan::X509_CRL& ecdsa_crl) :
2✔
66
            m_rsa_cert(rsa_cert),
2✔
67
            m_rsa_ca(rsa_ca),
2✔
68
            m_rsa_key(rsa_key),
2✔
69
            m_ecdsa_cert(ecdsa_cert),
2✔
70
            m_ecdsa_ca(ecdsa_ca),
2✔
71
            m_ecdsa_key(ecdsa_key) {
6✔
72
         auto store = std::make_unique<Botan::Certificate_Store_In_Memory>();
2✔
73
         store->add_certificate(m_rsa_ca);
2✔
74
         store->add_certificate(m_ecdsa_ca);
2✔
75
         store->add_crl(rsa_crl);
2✔
76
         store->add_crl(ecdsa_crl);
2✔
77

78
         m_stores.push_back(std::move(store));
2✔
79
         m_provides_client_certs = with_client_certs;
2✔
80
      }
2✔
81

82
      std::vector<Botan::Certificate_Store*> trusted_certificate_authorities(const std::string& /*type*/,
208✔
83
                                                                             const std::string& /*context*/) override {
84
         std::vector<Botan::Certificate_Store*> v;
208✔
85
         v.reserve(m_stores.size());
208✔
86
         for(const auto& store : m_stores) {
416✔
87
            v.push_back(store.get());
208✔
88
         }
89
         return v;
208✔
90
      }
×
91

92
      std::vector<Botan::X509_Certificate> find_cert_chain(const std::vector<std::string>& cert_key_types,
417✔
93
                                                           const std::vector<Botan::AlgorithmIdentifier>& /*unused*/,
94
                                                           const std::vector<Botan::X509_DN>& acceptable_CAs,
95
                                                           const std::string& type,
96
                                                           const std::string& context) override {
97
         BOTAN_UNUSED(context);
417✔
98
         std::vector<Botan::X509_Certificate> chain;
417✔
99

100
         if(m_acceptable_cas.empty()) {
417✔
101
            m_acceptable_cas = acceptable_CAs;
17✔
102
         }
103

104
         if(type == "tls-server" || (type == "tls-client" && m_provides_client_certs)) {
417✔
105
            for(const auto& key_type : cert_key_types) {
455✔
106
               if(key_type == "RSA") {
342✔
107
                  chain.push_back(m_rsa_cert);
116✔
108
                  chain.push_back(m_rsa_ca);
116✔
109
                  break;
110
               } else if(key_type == "ECDSA") {
226✔
111
                  chain.push_back(m_ecdsa_cert);
113✔
112
                  chain.push_back(m_ecdsa_ca);
113✔
113
                  break;
114
               }
115
            }
116
         }
117

118
         return chain;
417✔
119
      }
×
120

121
      std::shared_ptr<Botan::Private_Key> private_key_for(const Botan::X509_Certificate& crt,
99✔
122
                                                          const std::string& /*type*/,
123
                                                          const std::string& /*context*/) override {
124
         if(crt == m_rsa_cert) {
99✔
125
            return m_rsa_key;
30✔
126
         }
127
         if(crt == m_ecdsa_cert) {
69✔
128
            return m_ecdsa_key;
69✔
129
         }
130
         return nullptr;
×
131
      }
132

133
      Botan::secure_vector<uint8_t> session_ticket_key() override {
×
134
         return Botan::hex_decode_locked("AABBCCDDEEFF012345678012345678");
×
135
      }
136

137
      Botan::secure_vector<uint8_t> dtls_cookie_secret() override {
124✔
138
         return Botan::hex_decode_locked("4AEA5EAD279CADEB537A594DA0E9DE3A");
124✔
139
      }
140

141
      std::vector<Botan::TLS::ExternalPSK> find_preshared_keys(
26✔
142
         std::string_view host,
143
         Botan::TLS::Connection_Side whoami,
144
         const std::vector<std::string>& identities = {},
145
         const std::optional<std::string>& prf = std::nullopt) override {
146
         if(identities.empty()) {
26✔
147
            return find_preshared_keys(host, whoami, identities, prf);
×
148
         }
149

150
         std::vector<Botan::TLS::ExternalPSK> psks;
26✔
151

152
         if(host == "server.example.com") {
26✔
153
            // PSKs for server and client are equal. For the sake of clarity,
154
            // we're not simplifying this code further
155
            if(whoami == Botan::TLS::Connection_Side::Client) {
26✔
156
               psks.emplace_back(
13✔
157
                  std::string{}, "SHA-256", Botan::hex_decode_locked("20B602D1475F2DF888FCB60D2AE03AFD"));
26✔
158
            }
159

160
            if(whoami == Botan::TLS::Connection_Side::Server) {
26✔
161
               psks.emplace_back(
13✔
162
                  std::string{}, "SHA-256", Botan::hex_decode_locked("20B602D1475F2DF888FCB60D2AE03AFD"));
26✔
163
            }
164
         }
165

166
         return psks;
26✔
167
      }
26✔
168

169
      const std::vector<Botan::X509_DN>& get_acceptable_cas() const { return m_acceptable_cas; }
4✔
170

171
   private:
172
      Botan::X509_Certificate m_rsa_cert, m_rsa_ca;
173
      std::shared_ptr<Botan::Private_Key> m_rsa_key;
174

175
      Botan::X509_Certificate m_ecdsa_cert, m_ecdsa_ca;
176
      std::shared_ptr<Botan::Private_Key> m_ecdsa_key;
177

178
      std::vector<std::unique_ptr<Botan::Certificate_Store>> m_stores;
179
      bool m_provides_client_certs;
180
      std::vector<Botan::X509_DN> m_acceptable_cas;
181
};
182

183
std::shared_ptr<Credentials_Manager_Test> create_creds(Botan::RandomNumberGenerator& rng,
2✔
184
                                                       bool with_client_certs = false) {
185
   // rsa and ecdsa are required for the tls module
186
   const auto ecdsa_params = Botan::EC_Group::from_name("secp256r1");
2✔
187
   const size_t rsa_params = 1024;
2✔
188

189
   auto rsa_ca_key = std::make_unique<Botan::RSA_PrivateKey>(rng, rsa_params);
2✔
190
   auto rsa_srv_key = std::make_unique<Botan::RSA_PrivateKey>(rng, rsa_params);
2✔
191

192
   auto ecdsa_ca_key = std::make_unique<Botan::ECDSA_PrivateKey>(rng, ecdsa_params);
2✔
193
   auto ecdsa_srv_key = std::make_unique<Botan::ECDSA_PrivateKey>(rng, ecdsa_params);
2✔
194

195
   Botan::X509_Cert_Options rsa_ca_opts("RSA Test CA/VT");
2✔
196
   Botan::X509_Cert_Options ecdsa_ca_opts("ECDSA Test CA/VT");
2✔
197
   rsa_ca_opts.CA_key(1);
2✔
198
   ecdsa_ca_opts.CA_key(1);
2✔
199

200
   const Botan::X509_Certificate rsa_ca_cert =
2✔
201
      Botan::X509::create_self_signed_cert(rsa_ca_opts, *rsa_ca_key, "SHA-256", rng);
2✔
202
   const Botan::X509_Certificate ecdsa_ca_cert =
2✔
203
      Botan::X509::create_self_signed_cert(ecdsa_ca_opts, *ecdsa_ca_key, "SHA-256", rng);
2✔
204

205
   const Botan::X509_Cert_Options server_opts("server.example.com");
2✔
206

207
   const Botan::PKCS10_Request rsa_req = Botan::X509::create_cert_req(server_opts, *rsa_srv_key, "SHA-256", rng);
2✔
208
   const Botan::PKCS10_Request ecdsa_req = Botan::X509::create_cert_req(server_opts, *ecdsa_srv_key, "SHA-256", rng);
2✔
209

210
   Botan::X509_CA rsa_ca(rsa_ca_cert, *rsa_ca_key, "SHA-256", rng);
2✔
211
   Botan::X509_CA ecdsa_ca(ecdsa_ca_cert, *ecdsa_ca_key, "SHA-256", rng);
2✔
212

213
   typedef std::chrono::duration<int, std::ratio<31556926>> years;
2✔
214
   auto now = std::chrono::system_clock::now();
2✔
215

216
   const Botan::X509_Time start_time(now);
2✔
217
   const Botan::X509_Time end_time(now + years(1));
2✔
218

219
   const Botan::X509_Certificate rsa_srv_cert = rsa_ca.sign_request(rsa_req, rng, start_time, end_time);
2✔
220
   const Botan::X509_Certificate ecdsa_srv_cert = ecdsa_ca.sign_request(ecdsa_req, rng, start_time, end_time);
2✔
221

222
   Botan::X509_CRL rsa_crl = rsa_ca.new_crl(rng);
2✔
223
   Botan::X509_CRL ecdsa_crl = ecdsa_ca.new_crl(rng);
2✔
224

225
   // dsa support is optional
226
   std::unique_ptr<Botan::Private_Key> dsa_ca_key;
2✔
227
   std::unique_ptr<Botan::Private_Key> dsa_srv_key;
2✔
228
   std::unique_ptr<Botan::X509_CRL> dsa_crl;
2✔
229
   std::unique_ptr<Botan::X509_Certificate> dsa_srv_cert;
2✔
230
   std::unique_ptr<Botan::X509_Certificate> dsa_ca_cert;
2✔
231

232
   return std::make_shared<Credentials_Manager_Test>(with_client_certs,
2✔
233
                                                     rsa_srv_cert,
234
                                                     rsa_srv_key.release(),
4✔
235
                                                     rsa_ca_cert,
236
                                                     rsa_crl,
237
                                                     ecdsa_srv_cert,
238
                                                     ecdsa_srv_key.release(),
2✔
239
                                                     ecdsa_ca_cert,
240
                                                     ecdsa_crl);
4✔
241
}
4✔
242

243
class TLS_Handshake_Test final {
244
   public:
245
      TLS_Handshake_Test(const std::string& test_descr,
128✔
246
                         Botan::TLS::Protocol_Version offer_version,
247
                         const std::shared_ptr<Credentials_Manager_Test>& creds,
248
                         const std::shared_ptr<const Botan::TLS::Policy>& client_policy,
249
                         const std::shared_ptr<const Botan::TLS::Policy>& server_policy,
250
                         const std::shared_ptr<Botan::RandomNumberGenerator>& rng,
251
                         const std::shared_ptr<Botan::TLS::Session_Manager>& client_sessions,
252
                         const std::shared_ptr<Botan::TLS::Session_Manager>& server_sessions,
253
                         bool expect_client_auth) :
128✔
254
            m_offer_version(offer_version),
128✔
255
            m_results(test_descr),
128✔
256
            m_creds(creds),
128✔
257
            m_client_policy(client_policy),
128✔
258
            m_client_sessions(client_sessions),
128✔
259
            m_rng(rng),
128✔
260
            m_client_auth(expect_client_auth) {
128✔
261
         m_server_cb = std::make_shared<Test_Callbacks>(m_results, offer_version, m_s2c, m_server_recv);
128✔
262
         m_client_cb = std::make_shared<Test_Callbacks>(m_results, offer_version, m_c2s, m_client_recv);
128✔
263

264
         bool is_dtls = offer_version.is_datagram_protocol();
128✔
265

266
         m_server =
128✔
267
            std::make_unique<Botan::TLS::Server>(m_server_cb, server_sessions, m_creds, server_policy, m_rng, is_dtls);
128✔
268
      }
128✔
269

270
      void go();
271

272
      const Test::Result& results() const { return m_results; }
128✔
273

274
      void set_custom_client_tls_session_established_callback(
6✔
275
         std::function<void(const Botan::TLS::Session_Summary&)> clbk) {
276
         BOTAN_ASSERT_NONNULL(m_client_cb);
6✔
277
         m_client_cb->set_custom_tls_session_established_callback(std::move(clbk));
12✔
278
      }
6✔
279

280
      void set_custom_server_tls_session_established_callback(
6✔
281
         std::function<void(const Botan::TLS::Session_Summary&)> clbk) {
282
         BOTAN_ASSERT_NONNULL(m_server_cb);
6✔
283
         m_server_cb->set_custom_tls_session_established_callback(std::move(clbk));
12✔
284
      }
6✔
285

286
      void set_client_expected_handshake_alert(Botan::TLS::Alert alert) {
6✔
287
         BOTAN_ASSERT_NONNULL(m_client_cb);
6✔
288
         m_client_cb->set_expected_handshake_alert(alert);
6✔
289
      }
6✔
290

291
      void set_server_expected_handshake_alert(Botan::TLS::Alert alert) {
6✔
292
         BOTAN_ASSERT_NONNULL(m_server_cb);
6✔
293
         m_server_cb->set_expected_handshake_alert(alert);
6✔
294
      }
6✔
295

296
   private:
297
      class Test_Extension : public Botan::TLS::Extension {
298
         public:
299
            static Botan::TLS::Extension_Code static_type() {
300
               // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
301
               return static_cast<Botan::TLS::Extension_Code>(666);
302
            }
303

304
            Botan::TLS::Extension_Code type() const override { return static_type(); }
1,788✔
305

306
            std::vector<uint8_t> serialize(Botan::TLS::Connection_Side /*whoami*/) const override { return m_buf; }
314✔
307

308
            const std::vector<uint8_t>& value() const { return m_buf; }
309

310
            bool empty() const override { return false; }
314✔
311

312
            explicit Test_Extension(Botan::TLS::Connection_Side side) {
252✔
313
               const uint8_t client_extn[6] = {'c', 'l', 'i', 'e', 'n', 't'};
252✔
314
               const uint8_t server_extn[6] = {'s', 'e', 'r', 'v', 'e', 'r'};
252✔
315

316
               Botan::TLS::append_tls_length_value(
252✔
317
                  m_buf, (side == Botan::TLS::Connection_Side::Client) ? client_extn : server_extn, 6, 1);
252✔
318
            }
252✔
319

320
         private:
321
            std::vector<uint8_t> m_buf;
322
      };
323

324
      class Test_Callbacks final : public Botan::TLS::Callbacks {
325
         public:
326
            Test_Callbacks(Test::Result& results,
256✔
327
                           Botan::TLS::Protocol_Version expected_version,
328
                           std::vector<uint8_t>& outbound,
329
                           std::vector<uint8_t>& recv_buf) :
256✔
330
                  m_results(results), m_expected_version(expected_version), m_outbound(outbound), m_recv(recv_buf) {}
256✔
331

332
            Test_Callbacks(Test_Callbacks&&) = delete;
333
            Test_Callbacks(const Test_Callbacks&) = delete;
334
            Test_Callbacks& operator=(const Test_Callbacks&) = delete;
335
            Test_Callbacks& operator=(Test_Callbacks&&) = delete;
336

337
            ~Test_Callbacks() override {
256✔
338
               if(m_expected_handshake_alert.has_value()) {
256✔
339
                  m_results.test_failure("Expected: " + m_expected_handshake_alert->type_string() +
×
340
                                         " during handshake");
341
               }
342
            }
256✔
343

344
            void tls_emit_data(std::span<const uint8_t> bits) override {
2,275✔
345
               m_outbound.insert(m_outbound.end(), bits.begin(), bits.end());
2,275✔
346
            }
2,275✔
347

348
            void tls_record_received(uint64_t /*seq*/, std::span<const uint8_t> bits) override {
370✔
349
               m_recv.insert(m_recv.end(), bits.begin(), bits.end());
370✔
350
            }
370✔
351

352
            void tls_alert(Botan::TLS::Alert alert) override {
464✔
353
               // TODO test that it is a no_renegotiation alert
354

355
               if(m_expected_handshake_alert.has_value()) {
464✔
356
                  if(m_expected_handshake_alert->type() != alert.type()) {
12✔
357
                     m_results.test_failure("Got unexpected alert: " + alert.type_string() +
×
358
                                            " expected: " + m_expected_handshake_alert->type_string());
×
359
                  } else {
360
                     // acknowledge that the expected Alert was detected
361
                     m_results.test_note("saw expected alert: " + m_expected_handshake_alert->type_string());
36✔
362
                     m_expected_handshake_alert.reset();
12✔
363
                  }
364
               }
365
            }
464✔
366

367
            void tls_modify_extensions(Botan::TLS::Extensions& extn,
252✔
368
                                       Botan::TLS::Connection_Side which_side,
369
                                       Botan::TLS::Handshake_Type /* unused */) override {
370
               extn.add(new Test_Extension(which_side));
252✔
371

372
               // Insert an unsupported signature scheme as highest prio, to ensure we are tolerant of this
373
               if(auto sig_algs = extn.take<Botan::TLS::Signature_Algorithms>()) {
252✔
374
                  std::vector<Botan::TLS::Signature_Scheme> schemes = sig_algs->supported_schemes();
128✔
375
                  // 0x0301 is RSA PKCS1/SHA-224, which is not supported anymore
376
                  schemes.insert(schemes.begin(), 0x0301);
128✔
377
                  // This replaces the previous extension value
378
                  extn.add(new Botan::TLS::Signature_Algorithms(schemes));
128✔
379
               }
128✔
380
            }
252✔
381

382
            void tls_examine_extensions(const Botan::TLS::Extensions& extn,
252✔
383
                                        Botan::TLS::Connection_Side which_side,
384
                                        Botan::TLS::Handshake_Type /*unused*/) override {
385
               // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
386
               const auto extn_id = static_cast<Botan::TLS::Extension_Code>(666);
252✔
387
               Botan::TLS::Extension* test_extn = extn.get(extn_id);
252✔
388

389
               if(test_extn == nullptr) {
252✔
390
                  m_results.test_failure("Did not receive test extension from peer");
×
391
               } else {
392
                  Botan::TLS::Unknown_Extension* unknown_ext = dynamic_cast<Botan::TLS::Unknown_Extension*>(test_extn);
252✔
393

394
                  if(unknown_ext) {
252✔
395
                     const std::vector<uint8_t> val = unknown_ext->value();
252✔
396

397
                     if(m_results.test_eq("Expected size for test extn", val.size(), 7)) {
252✔
398
                        if(which_side == Botan::TLS::Connection_Side::Client) {
252✔
399
                           m_results.test_eq("Expected extension value", val, "06636C69656E74");
256✔
400
                        } else {
401
                           m_results.test_eq("Expected extension value", val, "06736572766572");
248✔
402
                        }
403
                     }
404
                  } else {
252✔
405
                     m_results.test_failure("Unknown extension type had unexpected type at runtime");
×
406
                  }
407
               }
408
            }
252✔
409

410
            void tls_session_established(const Botan::TLS::Session_Summary& session) override {
242✔
411
               const std::string session_report = "Session established " + session.version().to_string() + " " +
726✔
412
                                                  session.ciphersuite().to_string() + " " +
726✔
413
                                                  Botan::hex_encode(session.session_id().get());
484✔
414

415
               m_results.test_note(session_report);
242✔
416

417
               if(m_session_established_callback) {
242✔
418
                  m_session_established_callback(session);
12✔
419
               }
420

421
               if(session.version() != m_expected_version) {
230✔
422
                  m_results.test_failure("Expected " + m_expected_version.to_string() + " negotiated " +
×
423
                                         session.version().to_string());
12✔
424
               }
425
            }
230✔
426

427
            std::string tls_server_choose_app_protocol(const std::vector<std::string>& protos) override {
128✔
428
               m_results.test_eq("ALPN protocol count", protos.size(), 2);
128✔
429
               m_results.test_eq("ALPN protocol 1", protos[0], "test/1");
256✔
430
               m_results.test_eq("ALPN protocol 2", protos[1], "test/2");
256✔
431
               return "test/3";
128✔
432
            }
433

434
            std::unique_ptr<Botan::PK_Key_Agreement_Key> tls_generate_ephemeral_key(
160✔
435
               const std::variant<Botan::TLS::Group_Params, Botan::DL_Group>& group,
436
               Botan::RandomNumberGenerator& rng) override {
437
               if(std::holds_alternative<Botan::TLS::Group_Params>(group) &&
160✔
438
                  std::get<Botan::TLS::Group_Params>(group).wire_code() == 0xFEE1) {
155✔
439
                  const auto ec_group = Botan::EC_Group::from_name("numsp256d1");
×
440
                  return std::make_unique<Botan::ECDH_PrivateKey>(rng, ec_group);
×
441
               }
×
442

443
               return Botan::TLS::Callbacks::tls_generate_ephemeral_key(group, rng);
160✔
444
            }
445

446
            Botan::secure_vector<uint8_t> tls_ephemeral_key_agreement(
160✔
447
               const std::variant<Botan::TLS::Group_Params, Botan::DL_Group>& group,
448
               const Botan::PK_Key_Agreement_Key& private_key,
449
               const std::vector<uint8_t>& public_value,
450
               Botan::RandomNumberGenerator& rng,
451
               const Botan::TLS::Policy& policy) override {
452
               if(std::holds_alternative<Botan::TLS::Group_Params>(group) &&
160✔
453
                  std::get<Botan::TLS::Group_Params>(group).wire_code() == 0xFEE1) {
155✔
454
                  const auto ec_group = Botan::EC_Group::from_name("numsp256d1");
×
455
                  Botan::ECDH_PublicKey peer_key(ec_group, ec_group.OS2ECP(public_value));
×
456
                  Botan::PK_Key_Agreement ka(private_key, rng, "Raw");
×
457
                  return ka.derive_key(0, peer_key.public_value()).bits_of();
×
458
               }
×
459

460
               return Botan::TLS::Callbacks::tls_ephemeral_key_agreement(group, private_key, public_value, rng, policy);
160✔
461
            }
462

463
            void set_custom_tls_session_established_callback(
12✔
464
               std::function<void(const Botan::TLS::Session_Summary&)> clbk) {
465
               m_session_established_callback = std::move(clbk);
12✔
466
            }
467

468
            void set_expected_handshake_alert(Botan::TLS::Alert alert) { m_expected_handshake_alert = alert; }
12✔
469

470
         private:
471
            Test::Result& m_results;
472
            const Botan::TLS::Protocol_Version m_expected_version;
473
            std::vector<uint8_t>& m_outbound;
474
            std::vector<uint8_t>& m_recv;
475

476
            std::function<void(const Botan::TLS::Session_Summary&)> m_session_established_callback;
477
            std::optional<Botan::TLS::Alert> m_expected_handshake_alert;
478
      };
479

480
      const Botan::TLS::Protocol_Version m_offer_version;
481
      Test::Result m_results;
482

483
      std::shared_ptr<Credentials_Manager_Test> m_creds;
484
      std::shared_ptr<const Botan::TLS::Policy> m_client_policy;
485
      std::shared_ptr<Botan::TLS::Session_Manager> m_client_sessions;
486
      std::shared_ptr<Botan::RandomNumberGenerator> m_rng;
487

488
      std::shared_ptr<Test_Callbacks> m_client_cb;
489

490
      std::shared_ptr<Test_Callbacks> m_server_cb;
491
      std::unique_ptr<Botan::TLS::Server> m_server;
492

493
      const bool m_client_auth;
494

495
      std::vector<uint8_t> m_c2s, m_s2c, m_client_recv, m_server_recv;
496
};
497

498
void TLS_Handshake_Test::go() {
128✔
499
   m_results.start_timer();
128✔
500

501
   const std::vector<std::string> protocols_offered = {"test/1", "test/2"};
128✔
502

503
   // Choose random application data to send
504
   const size_t c_len = 1 + ((static_cast<size_t>(m_rng->next_byte()) << 4) ^ m_rng->next_byte());
128✔
505
   std::vector<uint8_t> client_msg(c_len);
128✔
506
   m_rng->randomize(client_msg.data(), client_msg.size());
128✔
507
   bool client_has_written = false;
128✔
508

509
   const size_t s_len = 1 + ((static_cast<size_t>(m_rng->next_byte()) << 4) ^ m_rng->next_byte());
128✔
510
   std::vector<uint8_t> server_msg(s_len);
128✔
511
   m_rng->randomize(server_msg.data(), server_msg.size());
128✔
512
   bool server_has_written = false;
128✔
513

514
   std::unique_ptr<Botan::TLS::Client> client;
128✔
515
   client = std::make_unique<Botan::TLS::Client>(m_client_cb,
128✔
516
                                                 m_client_sessions,
128✔
517
                                                 m_creds,
128✔
518
                                                 m_client_policy,
128✔
519
                                                 m_rng,
128✔
520
                                                 Botan::TLS::Server_Information("server.example.com"),
128✔
521
                                                 m_offer_version,
128✔
522
                                                 protocols_offered);
128✔
523

524
   size_t rounds = 0;
128✔
525

526
   bool client_handshake_completed = false;
128✔
527
   bool server_handshake_completed = false;
128✔
528

529
   while(true) {
1,195✔
530
      ++rounds;
1,195✔
531

532
      if(rounds > 25) {
1,195✔
533
         m_results.test_failure("Still here after many rounds, deadlock?");
×
534
         break;
×
535
      }
536

537
      if(client_handshake_completed == false && client->is_active()) {
1,195✔
538
         client_handshake_completed = true;
539
      }
540

541
      if(server_handshake_completed == false && m_server->is_active()) {
1,195✔
542
         server_handshake_completed = true;
543
      }
544

545
      if(client->is_active() && client_has_written == false) {
1,195✔
546
         m_results.test_eq("client ALPN protocol", client->application_protocol(), "test/3");
224✔
547

548
         size_t sent_so_far = 0;
112✔
549
         while(sent_so_far != client_msg.size()) {
298✔
550
            const size_t left = client_msg.size() - sent_so_far;
186✔
551
            const size_t rnd12 = (m_rng->next_byte() << 4) ^ m_rng->next_byte();
186✔
552
            const size_t sending = std::min(left, rnd12);
186✔
553

554
            client->send(&client_msg[sent_so_far], sending);
186✔
555
            sent_so_far += sending;
186✔
556
         }
557
         client->send_warning_alert(Botan::TLS::Alert::NoRenegotiation);
112✔
558
         client_has_written = true;
559
      }
560

561
      if(m_server->is_active() && server_has_written == false) {
1,195✔
562
         m_results.test_eq("server ALPN protocol", m_server->application_protocol(), "test/3");
236✔
563

564
         size_t sent_so_far = 0;
118✔
565
         while(sent_so_far != server_msg.size()) {
313✔
566
            const size_t left = server_msg.size() - sent_so_far;
195✔
567
            const size_t rnd12 = (m_rng->next_byte() << 4) ^ m_rng->next_byte();
195✔
568
            const size_t sending = std::min(left, rnd12);
195✔
569

570
            m_server->send(&server_msg[sent_so_far], sending);
195✔
571
            sent_so_far += sending;
195✔
572
         }
573

574
         m_server->send_warning_alert(Botan::TLS::Alert::NoRenegotiation);
118✔
575
         server_has_written = true;
576
      }
577

578
      if(!m_c2s.empty()) {
1,195✔
579
         /*
580
         * Use this as a temp value to hold the queues as otherwise they
581
         * might end up appending more in response to messages during the
582
         * handshake.
583
         */
584
         std::vector<uint8_t> input;
529✔
585
         std::swap(m_c2s, input);
529✔
586

587
         try {
529✔
588
            size_t needed = m_server->received_data(input.data(), input.size());
529✔
589
            m_results.test_eq("full packet received", needed, 0);
1,038✔
590
         } catch(...) { /* ignore exceptions */
10✔
591
         }
10✔
592

593
         continue;
529✔
594
      }
529✔
595

596
      if(!m_s2c.empty()) {
666✔
597
         std::vector<uint8_t> input;
426✔
598
         std::swap(m_s2c, input);
426✔
599

600
         try {
426✔
601
            size_t needed = client->received_data(input.data(), input.size());
426✔
602
            m_results.test_eq("full packet received", needed, 0);
840✔
603
         } catch(...) { /* ignore exceptions */
6✔
604
         }
6✔
605

606
         continue;
426✔
607
      }
426✔
608

609
      if(!m_client_recv.empty()) {
240✔
610
         m_results.test_eq("client recv", m_client_recv, server_msg);
448✔
611
      }
612

613
      if(!m_server_recv.empty()) {
240✔
614
         m_results.test_eq("server recv", m_server_recv, client_msg);
448✔
615
      }
616

617
      if(client->is_closed() && m_server->is_closed()) {
240✔
618
         break;
619
      }
620

621
      if(m_server->is_active()) {
112✔
622
         std::vector<Botan::X509_Certificate> certs = m_server->peer_cert_chain();
112✔
623
         if(m_client_auth) {
112✔
624
            m_results.test_eq("got client certs", certs.size(), 2);
4✔
625

626
            std::vector<Botan::X509_DN> acceptable_CAs = m_creds->get_acceptable_cas();
4✔
627

628
            m_results.test_eq("client got CA list", acceptable_CAs.size(), 2);  // RSA + ECDSA
4✔
629

630
            for(const Botan::X509_DN& dn : acceptable_CAs) {
12✔
631
               m_results.test_eq("Expected CA country field", dn.get_first_attribute("C"), "VT");
16✔
632
            }
633
         } else {
4✔
634
            m_results.test_eq("no client certs", certs.size(), 0);
216✔
635
         }
636
      }
112✔
637

638
      if(!m_server_recv.empty() && !m_client_recv.empty()) {
112✔
639
         Botan::SymmetricKey client_key = client->key_material_export("label", "context", 32);
112✔
640
         Botan::SymmetricKey server_key = m_server->key_material_export("label", "context", 32);
112✔
641

642
         m_results.test_eq("TLS key material export", client_key.bits_of(), server_key.bits_of());
336✔
643

644
         m_results.confirm("Client is active", client->is_active());
224✔
645
         m_results.confirm("Client is not closed", !client->is_closed());
224✔
646
         client->close();
112✔
647
         m_results.confirm("Client is no longer active", !client->is_active());
224✔
648
         m_results.confirm("Client is closed", client->is_closed());
224✔
649
      }
224✔
650
   }
651

652
   m_results.end_timer();
128✔
653
}
384✔
654

655
class Test_Policy final : public Botan::TLS::Text_Policy {
29✔
656
   public:
657
      Test_Policy() : Text_Policy("") {}
29✔
658

659
      bool acceptable_protocol_version(Botan::TLS::Protocol_Version version) const override {
593✔
660
         // TODO: handle TLS 1.3 server once the time is ripe.
661
         return version.is_pre_tls_13();
593✔
662
      }
663

664
      size_t dtls_initial_timeout() const override { return 1; }
124✔
665

666
      size_t dtls_maximum_timeout() const override { return 8; }
124✔
667

668
      size_t minimum_rsa_bits() const override { return 1024; }
12✔
669

670
      size_t minimum_signature_strength() const override { return 80; }
95✔
671
};
672

673
class TLS_Unit_Tests final : public Test {
×
674
   private:
675
      static void test_with_policy(const std::string& test_descr,
30✔
676
                                   std::vector<Test::Result>& results,
677
                                   const std::shared_ptr<Botan::TLS::Session_Manager>& client_ses,
678
                                   const std::shared_ptr<Botan::TLS::Session_Manager>& server_ses,
679
                                   const std::shared_ptr<Credentials_Manager_Test>& creds,
680
                                   const std::vector<Botan::TLS::Protocol_Version>& versions,
681
                                   const std::shared_ptr<const Botan::TLS::Policy>& policy,
682
                                   std::shared_ptr<Botan::RandomNumberGenerator>& rng,
683
                                   bool client_auth = false) {
684
         try {
30✔
685
            for(const auto& version : versions) {
88✔
686
               TLS_Handshake_Test test(version.to_string() + " " + test_descr,
116✔
687
                                       version,
688
                                       creds,
689
                                       policy,
690
                                       policy,
691
                                       rng,
692
                                       client_ses,
693
                                       server_ses,
694
                                       client_auth);
116✔
695
               test.go();
58✔
696
               results.push_back(test.results());
58✔
697

698
               TLS_Handshake_Test test_resumption(version.to_string() + " " + test_descr,
174✔
699
                                                  version,
700
                                                  creds,
701
                                                  policy,
702
                                                  policy,
703
                                                  rng,
704
                                                  client_ses,
705
                                                  server_ses,
706
                                                  client_auth);
58✔
707
               test_resumption.go();
58✔
708
               results.push_back(test_resumption.results());
58✔
709
            }
58✔
710
         } catch(std::exception& e) {
×
711
            results.push_back(Test::Result::Failure(test_descr, e.what()));
×
712
         }
×
713
      }
30✔
714

715
      static void test_all_versions(const std::string& test_descr,
8✔
716
                                    std::vector<Test::Result>& results,
717
                                    const std::shared_ptr<Botan::TLS::Session_Manager>& client_ses,
718
                                    const std::shared_ptr<Botan::TLS::Session_Manager>& server_ses,
719
                                    const std::shared_ptr<Credentials_Manager_Test>& creds,
720
                                    std::shared_ptr<Botan::RandomNumberGenerator>& rng,
721
                                    const std::string& kex_policy,
722
                                    const std::string& cipher_policy,
723
                                    const std::string& mac_policy,
724
                                    const std::string& etm_policy,
725
                                    bool client_auth = false) {
726
         auto policy = std::make_shared<Test_Policy>();
8✔
727
         policy->set("ciphers", cipher_policy);
8✔
728
         policy->set("macs", mac_policy);
8✔
729
         policy->set("key_exchange_methods", kex_policy);
8✔
730
         policy->set("negotiate_encrypt_then_mac", etm_policy);
8✔
731

732
         policy->set("allow_tls12", "true");
16✔
733
         policy->set("allow_dtls12", "true");
16✔
734

735
         if(kex_policy.find("RSA") != std::string::npos) {
8✔
736
            policy->set("signature_methods", "IMPLICIT");
8✔
737
         }
738

739
         std::vector<Botan::TLS::Protocol_Version> versions = {Botan::TLS::Protocol_Version::TLS_V12,
8✔
740
                                                               Botan::TLS::Protocol_Version::DTLS_V12};
8✔
741

742
         return test_with_policy(
8✔
743
            test_descr, results, client_ses, server_ses, creds, versions, policy, rng, client_auth);
8✔
744
      }
16✔
745

746
      static void test_modern_versions(const std::string& test_descr,
12✔
747
                                       std::vector<Test::Result>& results,
748
                                       const std::shared_ptr<Botan::TLS::Session_Manager>& client_ses,
749
                                       const std::shared_ptr<Botan::TLS::Session_Manager>& server_ses,
750
                                       const std::shared_ptr<Credentials_Manager_Test>& creds,
751
                                       std::shared_ptr<Botan::RandomNumberGenerator>& rng,
752
                                       const std::string& kex_policy,
753
                                       const std::string& cipher_policy,
754
                                       const std::string& mac_policy = "AEAD",
755
                                       bool client_auth = false) {
756
         std::map<std::string, std::string> no_extra_policies;
12✔
757
         return test_modern_versions(test_descr,
12✔
758
                                     results,
759
                                     client_ses,
760
                                     server_ses,
761
                                     creds,
762
                                     rng,
763
                                     kex_policy,
764
                                     cipher_policy,
765
                                     mac_policy,
766
                                     no_extra_policies,
767
                                     client_auth);
12✔
768
      }
12✔
769

770
      static void test_modern_versions(const std::string& test_descr,
20✔
771
                                       std::vector<Test::Result>& results,
772
                                       const std::shared_ptr<Botan::TLS::Session_Manager>& client_ses,
773
                                       const std::shared_ptr<Botan::TLS::Session_Manager>& server_ses,
774
                                       const std::shared_ptr<Credentials_Manager_Test>& creds,
775
                                       std::shared_ptr<Botan::RandomNumberGenerator>& rng,
776
                                       const std::string& kex_policy,
777
                                       const std::string& cipher_policy,
778
                                       const std::string& mac_policy,
779
                                       const std::map<std::string, std::string>& extra_policies,
780
                                       bool client_auth = false) {
781
         auto policy = std::make_shared<Test_Policy>();
20✔
782
         policy->set("ciphers", cipher_policy);
20✔
783
         policy->set("macs", mac_policy);
20✔
784
         policy->set("key_exchange_methods", kex_policy);
20✔
785
         policy->set("allow_tls12", "true");
40✔
786
         policy->set("allow_dtls12", "true");
40✔
787

788
         if(kex_policy.find("RSA") != std::string::npos) {
20✔
789
            policy->set("signature_methods", "IMPLICIT");
2✔
790
         }
791

792
         for(const auto& kv : extra_policies) {
29✔
793
            policy->set(kv.first, kv.second);
9✔
794
         }
795

796
         std::vector<Botan::TLS::Protocol_Version> versions = {Botan::TLS::Protocol_Version::TLS_V12,
20✔
797
                                                               Botan::TLS::Protocol_Version::DTLS_V12};
20✔
798

799
         return test_with_policy(
20✔
800
            test_descr, results, client_ses, server_ses, creds, versions, policy, rng, client_auth);
20✔
801
      }
40✔
802

803
      void test_session_established_abort(std::vector<Test::Result>& results,
1✔
804
                                          std::shared_ptr<Credentials_Manager_Test> creds,
805
                                          std::shared_ptr<Botan::RandomNumberGenerator> rng) {
806
         std::vector<Botan::TLS::Protocol_Version> versions = {Botan::TLS::Protocol_Version::TLS_V12,
1✔
807
                                                               Botan::TLS::Protocol_Version::DTLS_V12};
1✔
808

809
         auto policy = std::make_shared<Test_Policy>();
1✔
810
         auto noop_session_manager = std::make_shared<Botan::TLS::Session_Manager_Noop>();
1✔
811

812
         auto client_aborts = [&](const std::exception_ptr& ex, Botan::TLS::Alert expected_server_alert) {
4✔
813
            for(const auto version : versions) {
9✔
814
               TLS_Handshake_Test test("Client aborts in tls_session_established with " +
12✔
815
                                          expected_server_alert.type_string() + ": " + version.to_string(),
24✔
816
                                       version,
817
                                       creds,
818
                                       policy,
819
                                       policy,
820
                                       rng,
821
                                       noop_session_manager,
822
                                       noop_session_manager,
823
                                       false);
30✔
824
               test.set_custom_client_tls_session_established_callback(
12✔
825
                  [=](const auto&) { std::rethrow_exception(ex); });
42✔
826
               test.set_server_expected_handshake_alert(expected_server_alert);
6✔
827

828
               test.go();
6✔
829
               results.push_back(test.results());
6✔
830
            }
6✔
831
         };
3✔
832

833
         auto server_aborts = [&](const std::exception_ptr& ex, Botan::TLS::Alert expected_server_alert) {
4✔
834
            for(const auto version : versions) {
9✔
835
               TLS_Handshake_Test test("Server aborts in tls_session_established with " +
12✔
836
                                          expected_server_alert.type_string() + ": " + version.to_string(),
24✔
837
                                       version,
838
                                       creds,
839
                                       policy,
840
                                       policy,
841
                                       rng,
842
                                       noop_session_manager,
843
                                       noop_session_manager,
844
                                       false);
30✔
845
               test.set_custom_server_tls_session_established_callback(
12✔
846
                  [=](const auto&) { std::rethrow_exception(ex); });
42✔
847
               test.set_client_expected_handshake_alert(expected_server_alert);
6✔
848

849
               test.go();
6✔
850
               results.push_back(test.results());
6✔
851
            }
6✔
852
         };
3✔
853

854
         client_aborts(std::make_exception_ptr(
3✔
855
                          Botan::TLS::TLS_Exception(Botan::TLS::Alert::AccessDenied, "some test TLS exception")),
1✔
856
                       Botan::TLS::Alert::AccessDenied);
857
         client_aborts(std::make_exception_ptr(Botan::Invalid_Authentication_Tag("some symmetric crypto failed :o)")),
2✔
858
                       Botan::TLS::Alert::BadRecordMac);
859
         client_aborts(std::make_exception_ptr(std::runtime_error("something strange happened")),
2✔
860
                       Botan::TLS::Alert::InternalError);
861

862
         server_aborts(std::make_exception_ptr(
3✔
863
                          Botan::TLS::TLS_Exception(Botan::TLS::Alert::AccessDenied, "some server test TLS exception")),
1✔
864
                       Botan::TLS::Alert::AccessDenied);
865
         server_aborts(std::make_exception_ptr(
2✔
866
                          Botan::Invalid_Authentication_Tag("some symmetric crypto failed in the server :o)")),
1✔
867
                       Botan::TLS::Alert::BadRecordMac);
868
         server_aborts(std::make_exception_ptr(std::runtime_error("something strange happened in the server")),
2✔
869
                       Botan::TLS::Alert::InternalError);
870
      }
2✔
871

872
   public:
873
      std::vector<Test::Result> run() override {
1✔
874
         std::vector<Test::Result> results;
1✔
875

876
         auto rng = Test::new_shared_rng(this->test_name());
1✔
877

878
         std::shared_ptr<Botan::TLS::Session_Manager> client_ses;
1✔
879
         std::shared_ptr<Botan::TLS::Session_Manager> server_ses;
1✔
880

881
   #if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
882
         client_ses = std::make_shared<Botan::TLS::Session_Manager_SQLite>("client pass", rng, ":memory:", 5);
1✔
883
         server_ses = std::make_shared<Botan::TLS::Session_Manager_SQLite>("server pass", rng, ":memory:", 5);
1✔
884
   #endif
885

886
         if(!client_ses) {
1✔
887
            client_ses = std::make_shared<Botan::TLS::Session_Manager_In_Memory>(rng);
×
888
         }
889

890
         if(!server_ses) {
1✔
891
            server_ses = std::make_shared<Botan::TLS::Session_Manager_In_Memory>(rng);
×
892
         }
893

894
         auto creds = create_creds(*rng);
1✔
895

896
   #if defined(BOTAN_HAS_TLS_CBC)
897
         for(std::string etm_setting : {"false", "true"}) {
3✔
898
            test_all_versions("AES-128 RSA",
4✔
899
                              results,
900
                              client_ses,
901
                              server_ses,
902
                              creds,
903
                              rng,
904
                              "RSA",
905
                              "AES-128",
906
                              "SHA-256 SHA-1",
907
                              etm_setting);
908
            test_all_versions("AES-128 ECDH",
4✔
909
                              results,
910
                              client_ses,
911
                              server_ses,
912
                              creds,
913
                              rng,
914
                              "ECDH",
915
                              "AES-128",
916
                              "SHA-256 SHA-1",
917
                              etm_setting);
918

919
      #if defined(BOTAN_HAS_DES)
920
            test_all_versions(
4✔
921
               "3DES RSA", results, client_ses, server_ses, creds, rng, "RSA", "3DES", "SHA-1", etm_setting);
922
            test_all_versions(
4✔
923
               "3DES ECDH", results, client_ses, server_ses, creds, rng, "ECDH", "3DES", "SHA-1", etm_setting);
924
      #endif
925

926
            server_ses->remove_all();
2✔
927
         }
2✔
928
         client_ses->remove_all();
1✔
929

930
         test_modern_versions("AES-128 DH", results, client_ses, server_ses, creds, rng, "DH", "AES-128", "SHA-256");
2✔
931

932
   #endif
933

934
         auto strict_policy = std::make_shared<Botan::TLS::Strict_Policy_Without_TLS13>();
1✔
935
         test_with_policy("Strict policy",
2✔
936
                          results,
937
                          client_ses,
938
                          server_ses,
939
                          creds,
940
                          {Botan::TLS::Protocol_Version::TLS_V12},
941
                          strict_policy,
942
                          rng);
943

944
         auto suiteb_128 = std::make_shared<Botan::TLS::NSA_Suite_B_128>();
1✔
945
         test_with_policy("Suite B",
2✔
946
                          results,
947
                          client_ses,
948
                          server_ses,
949
                          creds,
950
                          {Botan::TLS::Protocol_Version::TLS_V12},
951
                          suiteb_128,
952
                          rng);
953

954
         // Remove server sessions before client, so clients retry with session server doesn't know
955
         server_ses->remove_all();
1✔
956

957
         test_modern_versions("AES-128/GCM RSA", results, client_ses, server_ses, creds, rng, "RSA", "AES-128/GCM");
2✔
958
         test_modern_versions("AES-128/GCM ECDH", results, client_ses, server_ses, creds, rng, "ECDH", "AES-128/GCM");
2✔
959

960
         test_modern_versions("AES-128/GCM ECDH RSA",
3✔
961
                              results,
962
                              client_ses,
963
                              server_ses,
964
                              creds,
965
                              rng,
966
                              "ECDH",
967
                              "AES-128/GCM",
968
                              "AEAD",
969
                              {{"signature_methods", "RSA"}});
970

971
         test_modern_versions("AES-128/GCM ECDH no OCSP",
3✔
972
                              results,
973
                              client_ses,
974
                              server_ses,
975
                              creds,
976
                              rng,
977
                              "ECDH",
978
                              "AES-128/GCM",
979
                              "AEAD",
980
                              {{"support_cert_status_message", "false"}});
981

982
         client_ses->remove_all();
1✔
983

984
   #if defined(BOTAN_HAS_CAMELLIA) && defined(BOTAN_HAS_AEAD_GCM)
985
         test_modern_versions(
2✔
986
            "Camellia-128/GCM ECDH", results, client_ses, server_ses, creds, rng, "ECDH", "Camellia-128/GCM", "AEAD");
987
   #endif
988

989
   #if defined(BOTAN_HAS_ARIA)
990
         test_modern_versions(
2✔
991
            "ARIA/GCM ECDH", results, client_ses, server_ses, creds, rng, "ECDH", "ARIA-128/GCM", "AEAD");
992
   #endif
993

994
         test_modern_versions("AES-128/GCM point compression",
3✔
995
                              results,
996
                              client_ses,
997
                              server_ses,
998
                              creds,
999
                              rng,
1000
                              "ECDH",
1001
                              "AES-128/GCM",
1002
                              "AEAD",
1003
                              {{"use_ecc_point_compression", "true"}});
1004
         test_modern_versions("AES-256/GCM p521",
3✔
1005
                              results,
1006
                              client_ses,
1007
                              server_ses,
1008
                              creds,
1009
                              rng,
1010
                              "ECDH",
1011
                              "AES-256/GCM",
1012
                              "AEAD",
1013
                              {{"groups", "secp521r1"}});
1014
         test_modern_versions("AES-128/GCM bp256r1",
3✔
1015
                              results,
1016
                              client_ses,
1017
                              server_ses,
1018
                              creds,
1019
                              rng,
1020
                              "ECDH",
1021
                              "AES-128/GCM",
1022
                              "AEAD",
1023
                              {{"groups", "brainpool256r1"}});
1024

1025
   #if defined(BOTAN_HAS_X25519)
1026
         test_modern_versions("AES-128/GCM x25519",
3✔
1027
                              results,
1028
                              client_ses,
1029
                              server_ses,
1030
                              creds,
1031
                              rng,
1032
                              "ECDH",
1033
                              "AES-128/GCM",
1034
                              "AEAD",
1035
                              {{"groups", "x25519"}});
1036
   #endif
1037

1038
         test_modern_versions("AES-128/GCM FFDHE-2048",
3✔
1039
                              results,
1040
                              client_ses,
1041
                              server_ses,
1042
                              creds,
1043
                              rng,
1044
                              "DH",
1045
                              "AES-128/GCM",
1046
                              "AEAD",
1047
                              {{"groups", "ffdhe/ietf/2048"}});
1048

1049
         auto creds_with_client_cert = create_creds(*rng, true);
1✔
1050

1051
         client_ses->remove_all();
1✔
1052
         test_modern_versions("AES-256/GCM client certs",
2✔
1053
                              results,
1054
                              client_ses,
1055
                              server_ses,
1056
                              creds_with_client_cert,
1057
                              rng,
1058
                              "ECDH",
1059
                              "AES-256/GCM",
1060
                              "AEAD",
1061
                              true);
1062

1063
   #if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
1064
         client_ses = std::make_shared<Botan::TLS::Session_Manager_In_Memory>(rng);
2✔
1065
         server_ses = std::make_shared<Botan::TLS::Session_Manager_In_Memory>(rng);
2✔
1066
   #endif
1067

1068
   #if defined(BOTAN_HAS_AEAD_OCB)
1069
         test_modern_versions(
2✔
1070
            "AES-256/OCB ECDH", results, client_ses, server_ses, creds, rng, "ECDH", "AES-256/OCB(12)");
1071
   #endif
1072

1073
         server_ses->remove_all();
1✔
1074

1075
   #if defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
1076
         test_modern_versions(
2✔
1077
            "ChaCha20Poly1305 ECDH", results, client_ses, server_ses, creds, rng, "ECDH", "ChaCha20Poly1305");
1078
   #endif
1079

1080
         test_modern_versions("AES-128/GCM PSK", results, client_ses, server_ses, creds, rng, "PSK", "AES-128/GCM");
2✔
1081

1082
   #if defined(BOTAN_HAS_AEAD_CCM)
1083
         test_modern_versions("AES-128/CCM PSK", results, client_ses, server_ses, creds, rng, "PSK", "AES-128/CCM");
2✔
1084
         test_modern_versions(
2✔
1085
            "AES-128/CCM-8 PSK", results, client_ses, server_ses, creds, rng, "PSK", "AES-128/CCM(8)");
1086
   #endif
1087

1088
         test_modern_versions(
2✔
1089
            "AES-128/GCM ECDHE_PSK", results, client_ses, server_ses, creds, rng, "ECDHE_PSK", "AES-128/GCM");
1090

1091
         // Test with a custom curve
1092

1093
         /*
1094
         * First register a curve, in this case numsp256d1
1095
         */
1096
         const Botan::BigInt p("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43");
1✔
1097
         const Botan::BigInt a("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40");
1✔
1098
         const Botan::BigInt b("0x25581");
1✔
1099
         const Botan::BigInt order("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE43C8275EA265C6020AB20294751A825");
1✔
1100

1101
         const Botan::BigInt g_x("0x01");
1✔
1102
         const Botan::BigInt g_y("0x696F1853C1E466D7FC82C96CCEEEDD6BD02C2F9375894EC10BF46306C2B56C77");
1✔
1103

1104
         const Botan::OID oid("1.3.6.1.4.1.25258.4.1");
1✔
1105

1106
         Botan::OID::register_oid(oid, "numsp256d1");
1✔
1107

1108
         // Creating this object implicitly registers the curve for future use ...
1109
         Botan::EC_Group reg_numsp256d1(oid, p, a, b, g_x, g_y, order);
1✔
1110

1111
         test_modern_versions("AES-256/GCM numsp256d1",
4✔
1112
                              results,
1113
                              client_ses,
1114
                              server_ses,
1115
                              creds,
1116
                              rng,
1117
                              "ECDH",
1118
                              "AES-256/GCM",
1119
                              "AEAD",
1120
                              {{"groups", "0xFEE1"}, {"minimum_ecdh_group_size", "112"}});
1121

1122
         // Test connection abort by the application
1123
         // by throwing in Callbacks::tls_session_established()
1124

1125
         test_session_established_abort(results, creds, rng);
2✔
1126

1127
         return results;
2✔
1128
      }
22✔
1129
};
1130

1131
BOTAN_REGISTER_TEST("tls", "unit_tls", TLS_Unit_Tests);
1132

1133
class DTLS_Reconnection_Test : public Test {
×
1134
   public:
1135
      std::vector<Test::Result> run() override {
1✔
1136
         class Test_Callbacks : public Botan::TLS::Callbacks {
4✔
1137
            public:
1138
               Test_Callbacks(Test::Result& results, std::vector<uint8_t>& outbound, std::vector<uint8_t>& recv_buf) :
3✔
1139
                     m_results(results), m_outbound(outbound), m_recv(recv_buf) {}
3✔
1140

1141
               void tls_emit_data(std::span<const uint8_t> bits) override {
28✔
1142
                  m_outbound.insert(m_outbound.end(), bits.begin(), bits.end());
28✔
1143
               }
28✔
1144

1145
               void tls_record_received(uint64_t /*seq*/, std::span<const uint8_t> bits) override {
4✔
1146
                  m_recv.insert(m_recv.end(), bits.begin(), bits.end());
4✔
1147
               }
4✔
1148

1149
               void tls_alert(Botan::TLS::Alert /*alert*/) override {
×
1150
                  // ignore
1151
               }
×
1152

1153
               void tls_session_established(const Botan::TLS::Session_Summary& /*session*/) override {
4✔
1154
                  m_results.test_success("Established a session");
4✔
1155
               }
4✔
1156

1157
            private:
1158
               Test::Result& m_results;
1159
               std::vector<uint8_t>& m_outbound;
1160
               std::vector<uint8_t>& m_recv;
1161
         };
1162

1163
         class Credentials_PSK : public Botan::Credentials_Manager {
3✔
1164
            public:
1165
               Botan::SymmetricKey psk(const std::string& type,
8✔
1166
                                       const std::string& context,
1167
                                       const std::string& /*identity*/) override {
1168
                  if(type == "tls-server" && context == "session-ticket") {
8✔
1169
                     return Botan::SymmetricKey("AABBCCDDEEFF012345678012345678");
×
1170
                  }
1171

1172
                  if(type == "tls-server" && context == "dtls-cookie-secret") {
8✔
1173
                     return Botan::SymmetricKey("4AEA5EAD279CADEB537A594DA0E9DE3A");
4✔
1174
                  }
1175

1176
                  if(context == "localhost" && type == "tls-client") {
4✔
1177
                     return Botan::SymmetricKey("20B602D1475F2DF888FCB60D2AE03AFD");
2✔
1178
                  }
1179

1180
                  if(context == "localhost" && type == "tls-server") {
2✔
1181
                     return Botan::SymmetricKey("20B602D1475F2DF888FCB60D2AE03AFD");
2✔
1182
                  }
1183

1184
                  throw Test_Error("No PSK set for " + type + "/" + context);
×
1185
               }
1186
         };
1187

1188
         class Datagram_PSK_Policy : public Botan::TLS::Policy {
5✔
1189
            public:
1190
               std::vector<std::string> allowed_macs() const override { return std::vector<std::string>({"AEAD"}); }
216✔
1191

1192
               std::vector<std::string> allowed_key_exchange_methods() const override { return {"PSK"}; }
4✔
1193

1194
               bool allow_tls12() const override { return false; }
6✔
1195

1196
               bool allow_dtls12() const override { return true; }
19✔
1197

1198
               bool allow_dtls_epoch0_restart() const override { return true; }
8✔
1199
         };
1200

1201
         Test::Result result("DTLS reconnection");
1✔
1202
         result.start_timer();
1✔
1203

1204
         auto rng = Test::new_shared_rng(this->test_name());
1✔
1205

1206
         auto server_policy = std::make_shared<Datagram_PSK_Policy>();
1✔
1207
         auto client_policy = std::make_shared<Datagram_PSK_Policy>();
1✔
1208
         auto creds = std::make_shared<Credentials_PSK>();
1✔
1209
         auto server_sessions = std::make_shared<Botan::TLS::Session_Manager_In_Memory>(rng);
1✔
1210
         auto client_sessions = std::make_shared<Botan::TLS::Session_Manager_Noop>();
1✔
1211

1212
         std::vector<uint8_t> s2c, server_recv;
1✔
1213
         auto server_callbacks = std::make_shared<Test_Callbacks>(result, s2c, server_recv);
1✔
1214
         Botan::TLS::Server server(server_callbacks, server_sessions, creds, server_policy, rng, true);
4✔
1215

1216
         std::vector<uint8_t> c1_c2s, client1_recv;
1✔
1217
         auto client1_callbacks = std::make_shared<Test_Callbacks>(result, c1_c2s, client1_recv);
1✔
1218
         Botan::TLS::Client client1(client1_callbacks,
1✔
1219
                                    client_sessions,
1220
                                    creds,
1221
                                    client_policy,
1222
                                    rng,
1223
                                    Botan::TLS::Server_Information("localhost"),
1✔
1224
                                    Botan::TLS::Protocol_Version::latest_dtls_version());
7✔
1225

1226
         bool c1_to_server_sent = false;
1✔
1227
         bool server_to_c1_sent = false;
1✔
1228

1229
         const std::vector<uint8_t> c1_to_server_magic(16, 0xC1);
1✔
1230
         const std::vector<uint8_t> server_to_c1_magic(16, 0x42);
1✔
1231

1232
         size_t c1_rounds = 0;
1✔
1233
         for(;;) {
10✔
1234
            c1_rounds++;
10✔
1235

1236
            if(c1_rounds > 64) {
10✔
1237
               result.test_failure("Still spinning in client1 loop after 64 rounds");
×
1238
               return {result};
×
1239
            }
1240

1241
            if(!c1_c2s.empty()) {
10✔
1242
               std::vector<uint8_t> input;
4✔
1243
               std::swap(c1_c2s, input);
4✔
1244
               server.received_data(input.data(), input.size());
4✔
1245
               continue;
4✔
1246
            }
4✔
1247

1248
            if(!s2c.empty()) {
6✔
1249
               std::vector<uint8_t> input;
4✔
1250
               std::swap(s2c, input);
4✔
1251
               client1.received_data(input.data(), input.size());
4✔
1252
               continue;
4✔
1253
            }
4✔
1254

1255
            if(!c1_to_server_sent && client1.is_active()) {
2✔
1256
               client1.send(c1_to_server_magic);
1✔
1257
               c1_to_server_sent = true;
1✔
1258
            }
1259

1260
            if(!server_to_c1_sent && server.is_active()) {
2✔
1261
               server.send(server_to_c1_magic);
2✔
1262
            }
1263

1264
            if(!server_recv.empty() && !client1_recv.empty()) {
2✔
1265
               result.test_eq("Expected message from client1", server_recv, c1_to_server_magic);
1✔
1266
               result.test_eq("Expected message to client1", client1_recv, server_to_c1_magic);
1✔
1267
               break;
1✔
1268
            }
1269
         }
1270

1271
         // Now client1 "goes away" (goes silent) and new client
1272
         // connects to same server context (ie due to reuse of client source port)
1273
         // See RFC 6347 section 4.2.8
1274

1275
         server_recv.clear();
1✔
1276
         s2c.clear();
1✔
1277

1278
         std::vector<uint8_t> c2_c2s, client2_recv;
1✔
1279
         auto client2_callbacks = std::make_shared<Test_Callbacks>(result, c2_c2s, client2_recv);
1✔
1280
         Botan::TLS::Client client2(client2_callbacks,
1✔
1281
                                    client_sessions,
1282
                                    creds,
1283
                                    client_policy,
1284
                                    rng,
1285
                                    Botan::TLS::Server_Information("localhost"),
1✔
1286
                                    Botan::TLS::Protocol_Version::latest_dtls_version());
7✔
1287

1288
         bool c2_to_server_sent = false;
1✔
1289
         bool server_to_c2_sent = false;
1✔
1290

1291
         const std::vector<uint8_t> c2_to_server_magic(16, 0xC2);
1✔
1292
         const std::vector<uint8_t> server_to_c2_magic(16, 0x66);
1✔
1293

1294
         size_t c2_rounds = 0;
1✔
1295

1296
         for(;;) {
10✔
1297
            c2_rounds++;
10✔
1298

1299
            if(c2_rounds > 64) {
10✔
1300
               result.test_failure("Still spinning in client2 loop after 64 rounds");
×
1301
               return {result};
×
1302
            }
1303

1304
            if(!c2_c2s.empty()) {
10✔
1305
               std::vector<uint8_t> input;
4✔
1306
               std::swap(c2_c2s, input);
4✔
1307
               server.received_data(input.data(), input.size());
4✔
1308
               continue;
4✔
1309
            }
4✔
1310

1311
            if(!s2c.empty()) {
6✔
1312
               std::vector<uint8_t> input;
4✔
1313
               std::swap(s2c, input);
4✔
1314
               client2.received_data(input.data(), input.size());
4✔
1315
               continue;
4✔
1316
            }
4✔
1317

1318
            if(!c2_to_server_sent && client2.is_active()) {
2✔
1319
               client2.send(c2_to_server_magic);
1✔
1320
               c2_to_server_sent = true;
1✔
1321
            }
1322

1323
            if(!server_to_c2_sent && server.is_active()) {
2✔
1324
               server.send(server_to_c2_magic);
2✔
1325
            }
1326

1327
            if(!server_recv.empty() && !client2_recv.empty()) {
2✔
1328
               result.test_eq("Expected message from client2", server_recv, c2_to_server_magic);
1✔
1329
               result.test_eq("Expected message to client2", client2_recv, server_to_c2_magic);
1✔
1330
               break;
1✔
1331
            }
1332
         }
1333

1334
         result.end_timer();
1✔
1335
         return {result};
2✔
1336
      }
18✔
1337
};
1338

1339
BOTAN_REGISTER_TEST("tls", "tls_dtls_reconnect", DTLS_Reconnection_Test);
1340

1341
#endif
1342

1343
}  // namespace
1344

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

© 2025 Coveralls, Inc