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

randombit / botan / 5123321399

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

Pull #3558

github

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

75602 of 81986 relevant lines covered (92.21%)

11859779.3 hits per line

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

95.97
/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*/,
217✔
83
                                                                             const std::string& /*context*/) override {
84
         std::vector<Botan::Certificate_Store*> v;
217✔
85
         v.reserve(m_stores.size());
217✔
86
         for(const auto& store : m_stores) {
434✔
87
            v.push_back(store.get());
217✔
88
         }
89
         return v;
217✔
90
      }
×
91

92
      std::vector<Botan::X509_Certificate> find_cert_chain(const std::vector<std::string>& cert_key_types,
425✔
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);
425✔
98
         std::vector<Botan::X509_Certificate> chain;
425✔
99

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

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

118
         return chain;
425✔
119
      }
×
120

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

133
      Botan::SymmetricKey psk(const std::string& type,
156✔
134
                              const std::string& context,
135
                              const std::string& /*identity*/) override {
136
         if(type == "tls-server" && context == "session-ticket") {
156✔
137
            return Botan::SymmetricKey("AABBCCDDEEFF012345678012345678");
×
138
         }
139

140
         if(type == "tls-server" && context == "dtls-cookie-secret") {
156✔
141
            return Botan::SymmetricKey("4AEA5EAD279CADEB537A594DA0E9DE3A");
124✔
142
         }
143

144
         if(context == "server.example.com" && type == "tls-client") {
32✔
145
            return Botan::SymmetricKey("20B602D1475F2DF888FCB60D2AE03AFD");
16✔
146
         }
147

148
         if(context == "server.example.com" && type == "tls-server") {
16✔
149
            return Botan::SymmetricKey("20B602D1475F2DF888FCB60D2AE03AFD");
16✔
150
         }
151

152
         throw Test_Error("No PSK set for " + type + "/" + context);
×
153
      }
154

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

157
   private:
158
      Botan::X509_Certificate m_rsa_cert, m_rsa_ca;
159
      std::shared_ptr<Botan::Private_Key> m_rsa_key;
160

161
      Botan::X509_Certificate m_ecdsa_cert, m_ecdsa_ca;
162
      std::shared_ptr<Botan::Private_Key> m_ecdsa_key;
163

164
      std::vector<std::unique_ptr<Botan::Certificate_Store>> m_stores;
165
      bool m_provides_client_certs;
166
      std::vector<Botan::X509_DN> m_acceptable_cas;
167
};
168

169
std::shared_ptr<Credentials_Manager_Test> create_creds(Botan::RandomNumberGenerator& rng,
2✔
170
                                                       bool with_client_certs = false) {
171
   // rsa and ecdsa are required for the tls module
172
   const Botan::EC_Group ecdsa_params("secp256r1");
2✔
173
   const size_t rsa_params = 1024;
2✔
174

175
   auto rsa_ca_key = std::make_unique<Botan::RSA_PrivateKey>(rng, rsa_params);
2✔
176
   auto rsa_srv_key = std::make_unique<Botan::RSA_PrivateKey>(rng, rsa_params);
2✔
177

178
   auto ecdsa_ca_key = std::make_unique<Botan::ECDSA_PrivateKey>(rng, ecdsa_params);
2✔
179
   auto ecdsa_srv_key = std::make_unique<Botan::ECDSA_PrivateKey>(rng, ecdsa_params);
2✔
180

181
   Botan::X509_Cert_Options rsa_ca_opts("RSA Test CA/VT");
2✔
182
   Botan::X509_Cert_Options ecdsa_ca_opts("ECDSA Test CA/VT");
2✔
183
   rsa_ca_opts.CA_key(1);
2✔
184
   ecdsa_ca_opts.CA_key(1);
2✔
185

186
   const Botan::X509_Certificate rsa_ca_cert =
2✔
187
      Botan::X509::create_self_signed_cert(rsa_ca_opts, *rsa_ca_key, "SHA-256", rng);
2✔
188
   const Botan::X509_Certificate ecdsa_ca_cert =
2✔
189
      Botan::X509::create_self_signed_cert(ecdsa_ca_opts, *ecdsa_ca_key, "SHA-256", rng);
2✔
190

191
   const Botan::X509_Cert_Options server_opts("server.example.com");
2✔
192

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

196
   Botan::X509_CA rsa_ca(rsa_ca_cert, *rsa_ca_key, "SHA-256", rng);
2✔
197
   Botan::X509_CA ecdsa_ca(ecdsa_ca_cert, *ecdsa_ca_key, "SHA-256", rng);
2✔
198

199
   typedef std::chrono::duration<int, std::ratio<31556926>> years;
2✔
200
   auto now = std::chrono::system_clock::now();
2✔
201

202
   const Botan::X509_Time start_time(now);
2✔
203
   const Botan::X509_Time end_time(now + years(1));
2✔
204

205
   const Botan::X509_Certificate rsa_srv_cert = rsa_ca.sign_request(rsa_req, rng, start_time, end_time);
2✔
206
   const Botan::X509_Certificate ecdsa_srv_cert = ecdsa_ca.sign_request(ecdsa_req, rng, start_time, end_time);
2✔
207

208
   Botan::X509_CRL rsa_crl = rsa_ca.new_crl(rng);
2✔
209
   Botan::X509_CRL ecdsa_crl = ecdsa_ca.new_crl(rng);
2✔
210

211
   // dsa support is optional
212
   std::unique_ptr<Botan::Private_Key> dsa_ca_key;
2✔
213
   std::unique_ptr<Botan::Private_Key> dsa_srv_key;
2✔
214
   std::unique_ptr<Botan::X509_CRL> dsa_crl;
2✔
215
   std::unique_ptr<Botan::X509_Certificate> dsa_srv_cert;
2✔
216
   std::unique_ptr<Botan::X509_Certificate> dsa_ca_cert;
2✔
217

218
   return std::make_shared<Credentials_Manager_Test>(with_client_certs,
2✔
219
                                                     rsa_srv_cert,
220
                                                     rsa_srv_key.release(),
4✔
221
                                                     rsa_ca_cert,
222
                                                     rsa_crl,
223
                                                     ecdsa_srv_cert,
224
                                                     ecdsa_srv_key.release(),
2✔
225
                                                     ecdsa_ca_cert,
226
                                                     ecdsa_crl);
4✔
227
}
4✔
228

229
class TLS_Handshake_Test final {
230
   public:
231
      TLS_Handshake_Test(const std::string& test_descr,
128✔
232
                         Botan::TLS::Protocol_Version offer_version,
233
                         const std::shared_ptr<Credentials_Manager_Test>& creds,
234
                         const std::shared_ptr<const Botan::TLS::Policy>& client_policy,
235
                         const std::shared_ptr<const Botan::TLS::Policy>& server_policy,
236
                         const std::shared_ptr<Botan::RandomNumberGenerator>& rng,
237
                         const std::shared_ptr<Botan::TLS::Session_Manager>& client_sessions,
238
                         const std::shared_ptr<Botan::TLS::Session_Manager>& server_sessions,
239
                         bool expect_client_auth) :
128✔
240
            m_offer_version(offer_version),
128✔
241
            m_results(test_descr),
128✔
242
            m_creds(creds),
128✔
243
            m_client_policy(client_policy),
128✔
244
            m_client_sessions(client_sessions),
128✔
245
            m_rng(rng),
128✔
246
            m_client_auth(expect_client_auth) {
128✔
247
         m_server_cb = std::make_shared<Test_Callbacks>(m_results, offer_version, m_s2c, m_server_recv);
128✔
248
         m_client_cb = std::make_shared<Test_Callbacks>(m_results, offer_version, m_c2s, m_client_recv);
128✔
249

250
         bool is_dtls = offer_version.is_datagram_protocol();
128✔
251

252
         m_server =
128✔
253
            std::make_unique<Botan::TLS::Server>(m_server_cb, server_sessions, m_creds, server_policy, m_rng, is_dtls);
128✔
254
      }
128✔
255

256
      void go();
257

258
      const Test::Result& results() const { return m_results; }
128✔
259

260
      void set_custom_client_tls_session_established_callback(
6✔
261
         std::function<void(const Botan::TLS::Session_Summary&)> clbk) {
262
         BOTAN_ASSERT_NONNULL(m_client_cb);
6✔
263
         m_client_cb->set_custom_tls_session_established_callback(std::move(clbk));
12✔
264
      }
6✔
265

266
      void set_custom_server_tls_session_established_callback(
6✔
267
         std::function<void(const Botan::TLS::Session_Summary&)> clbk) {
268
         BOTAN_ASSERT_NONNULL(m_server_cb);
6✔
269
         m_server_cb->set_custom_tls_session_established_callback(std::move(clbk));
12✔
270
      }
6✔
271

272
      void set_client_expected_handshake_alert(Botan::TLS::Alert alert) {
6✔
273
         BOTAN_ASSERT_NONNULL(m_client_cb);
6✔
274
         m_client_cb->set_expected_handshake_alert(alert);
6✔
275
      }
6✔
276

277
      void set_server_expected_handshake_alert(Botan::TLS::Alert alert) {
6✔
278
         BOTAN_ASSERT_NONNULL(m_server_cb);
6✔
279
         m_server_cb->set_expected_handshake_alert(alert);
6✔
280
      }
6✔
281

282
   private:
283
      class Test_Extension : public Botan::TLS::Extension {
284
         public:
285
            static Botan::TLS::Extension_Code static_type() { return static_cast<Botan::TLS::Extension_Code>(666); }
286

287
            Botan::TLS::Extension_Code type() const override { return static_type(); }
1,837✔
288

289
            std::vector<uint8_t> serialize(Botan::TLS::Connection_Side /*whoami*/) const override { return m_buf; }
318✔
290

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

293
            bool empty() const override { return false; }
318✔
294

295
            explicit Test_Extension(Botan::TLS::Connection_Side side) {
256✔
296
               const uint8_t client_extn[6] = {'c', 'l', 'i', 'e', 'n', 't'};
256✔
297
               const uint8_t server_extn[6] = {'s', 'e', 'r', 'v', 'e', 'r'};
256✔
298

299
               Botan::TLS::append_tls_length_value(
384✔
300
                  m_buf, (side == Botan::TLS::Connection_Side::Client) ? client_extn : server_extn, 6, 1);
301
            }
256✔
302

303
         private:
304
            std::vector<uint8_t> m_buf;
305
      };
306

307
      class Test_Callbacks final : public Botan::TLS::Callbacks {
308
         public:
309
            Test_Callbacks(Test::Result& results,
256✔
310
                           Botan::TLS::Protocol_Version expected_version,
311
                           std::vector<uint8_t>& outbound,
312
                           std::vector<uint8_t>& recv_buf) :
256✔
313
                  m_results(results), m_expected_version(expected_version), m_outbound(outbound), m_recv(recv_buf) {}
256✔
314

315
            Test_Callbacks(Test_Callbacks&&) = delete;
316
            Test_Callbacks(const Test_Callbacks&) = delete;
317
            Test_Callbacks& operator=(const Test_Callbacks&) = delete;
318
            Test_Callbacks& operator=(Test_Callbacks&&) = delete;
319

320
            ~Test_Callbacks() override {
256✔
321
               if(m_expected_handshake_alert.has_value()) {
256✔
322
                  m_results.test_failure("Expected: " + m_expected_handshake_alert->type_string() +
×
323
                                         " during handshake");
324
               }
325
            }
256✔
326

327
            void tls_emit_data(std::span<const uint8_t> bits) override {
2,362✔
328
               m_outbound.insert(m_outbound.end(), bits.begin(), bits.end());
2,362✔
329
            }
2,362✔
330

331
            void tls_record_received(uint64_t /*seq*/, std::span<const uint8_t> bits) override {
399✔
332
               m_recv.insert(m_recv.end(), bits.begin(), bits.end());
399✔
333
            }
399✔
334

335
            void tls_alert(Botan::TLS::Alert alert) override {
476✔
336
               // TODO test that it is a no_renegotiation alert
337

338
               if(m_expected_handshake_alert.has_value()) {
476✔
339
                  if(m_expected_handshake_alert->type() != alert.type()) {
12✔
340
                     m_results.test_failure("Got unexpected alert: " + alert.type_string() +
×
341
                                            " expected: " + m_expected_handshake_alert->type_string());
×
342
                  } else {
343
                     // acknowledge that the expected Alert was detected
344
                     m_results.test_note("saw expected alert: " + m_expected_handshake_alert->type_string());
24✔
345
                     m_expected_handshake_alert.reset();
12✔
346
                  }
347
               }
348
            }
476✔
349

350
            void tls_modify_extensions(Botan::TLS::Extensions& extn,
256✔
351
                                       Botan::TLS::Connection_Side which_side,
352
                                       Botan::TLS::Handshake_Type /* unused */) override {
353
               extn.add(new Test_Extension(which_side));
256✔
354

355
               // Insert an unsupported signature scheme as highest prio, to ensure we are tolerant of this
356
               if(auto sig_algs = extn.take<Botan::TLS::Signature_Algorithms>()) {
256✔
357
                  std::vector<Botan::TLS::Signature_Scheme> schemes = sig_algs->supported_schemes();
128✔
358
                  // 0x0301 is RSA PKCS1/SHA-224, which is not supported anymore
359
                  schemes.insert(schemes.begin(), 0x0301);
128✔
360
                  // This replaces the previous extension value
361
                  extn.add(new Botan::TLS::Signature_Algorithms(schemes));
256✔
362
               }
256✔
363
            }
256✔
364

365
            void tls_examine_extensions(const Botan::TLS::Extensions& extn,
256✔
366
                                        Botan::TLS::Connection_Side which_side,
367
                                        Botan::TLS::Handshake_Type /*unused*/) override {
368
               Botan::TLS::Extension* test_extn = extn.get(static_cast<Botan::TLS::Extension_Code>(666));
256✔
369

370
               if(test_extn == nullptr) {
256✔
371
                  m_results.test_failure("Did not receive test extension from peer");
×
372
               } else {
373
                  Botan::TLS::Unknown_Extension* unknown_ext = dynamic_cast<Botan::TLS::Unknown_Extension*>(test_extn);
256✔
374

375
                  if(unknown_ext) {
256✔
376
                     const std::vector<uint8_t> val = unknown_ext->value();
256✔
377

378
                     if(m_results.test_eq("Expected size for test extn", val.size(), 7)) {
512✔
379
                        if(which_side == Botan::TLS::Connection_Side::Client) {
256✔
380
                           m_results.test_eq("Expected extension value", val, "06636C69656E74");
256✔
381
                        } else {
382
                           m_results.test_eq("Expected extension value", val, "06736572766572");
256✔
383
                        }
384
                     }
385
                  } else {
256✔
386
                     m_results.test_failure("Unknown extension type had unexpected type at runtime");
×
387
                  }
388
               }
389
            }
256✔
390

391
            void tls_session_established(const Botan::TLS::Session_Summary& session) override {
250✔
392
               const std::string session_report = "Session established " + session.version().to_string() + " " +
500✔
393
                                                  session.ciphersuite().to_string() + " " +
1,000✔
394
                                                  Botan::hex_encode(session.session_id().get());
500✔
395

396
               m_results.test_note(session_report);
250✔
397

398
               if(m_session_established_callback) {
250✔
399
                  m_session_established_callback(session);
12✔
400
               }
401

402
               if(session.version() != m_expected_version) {
238✔
403
                  m_results.test_failure("Expected " + m_expected_version.to_string() + " negotiated " +
×
404
                                         session.version().to_string());
12✔
405
               }
406
            }
238✔
407

408
            std::string tls_server_choose_app_protocol(const std::vector<std::string>& protos) override {
128✔
409
               m_results.test_eq("ALPN protocol count", protos.size(), 2);
128✔
410
               m_results.test_eq("ALPN protocol 1", protos[0], "test/1");
256✔
411
               m_results.test_eq("ALPN protocol 2", protos[1], "test/2");
256✔
412
               return "test/3";
128✔
413
            }
414

415
            std::unique_ptr<Botan::PK_Key_Agreement_Key> tls_generate_ephemeral_key(
168✔
416
               const std::variant<Botan::TLS::Group_Params, Botan::DL_Group>& group,
417
               Botan::RandomNumberGenerator& rng) override {
418
               if(std::holds_alternative<Botan::TLS::Group_Params>(group) &&
168✔
419
                  static_cast<uint16_t>(std::get<Botan::TLS::Group_Params>(group)) == 0xFEE1) {
164✔
420
                  const Botan::EC_Group ec_group("secp112r1");
8✔
421
                  return std::make_unique<Botan::ECDH_PrivateKey>(rng, ec_group);
16✔
422
               }
8✔
423

424
               return Botan::TLS::Callbacks::tls_generate_ephemeral_key(group, rng);
160✔
425
            }
426

427
            Botan::secure_vector<uint8_t> tls_ephemeral_key_agreement(
168✔
428
               const std::variant<Botan::TLS::Group_Params, Botan::DL_Group>& group,
429
               const Botan::PK_Key_Agreement_Key& private_key,
430
               const std::vector<uint8_t>& public_value,
431
               Botan::RandomNumberGenerator& rng,
432
               const Botan::TLS::Policy& policy) override {
433
               if(std::holds_alternative<Botan::TLS::Group_Params>(group) &&
168✔
434
                  static_cast<uint16_t>(std::get<Botan::TLS::Group_Params>(group)) == 0xFEE1) {
164✔
435
                  const Botan::EC_Group ec_group("secp112r1");
8✔
436
                  Botan::ECDH_PublicKey peer_key(ec_group, ec_group.OS2ECP(public_value));
8✔
437
                  Botan::PK_Key_Agreement ka(private_key, rng, "Raw");
8✔
438
                  return ka.derive_key(0, peer_key.public_value()).bits_of();
16✔
439
               }
8✔
440

441
               return Botan::TLS::Callbacks::tls_ephemeral_key_agreement(group, private_key, public_value, rng, policy);
160✔
442
            }
443

444
            void set_custom_tls_session_established_callback(
12✔
445
               std::function<void(const Botan::TLS::Session_Summary&)> clbk) {
446
               m_session_established_callback = std::move(clbk);
12✔
447
            }
448

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

451
         private:
452
            Test::Result& m_results;
453
            const Botan::TLS::Protocol_Version m_expected_version;
454
            std::vector<uint8_t>& m_outbound;
455
            std::vector<uint8_t>& m_recv;
456

457
            std::function<void(const Botan::TLS::Session_Summary&)> m_session_established_callback;
458
            std::optional<Botan::TLS::Alert> m_expected_handshake_alert;
459
      };
460

461
      const Botan::TLS::Protocol_Version m_offer_version;
462
      Test::Result m_results;
463

464
      std::shared_ptr<Credentials_Manager_Test> m_creds;
465
      std::shared_ptr<const Botan::TLS::Policy> m_client_policy;
466
      std::shared_ptr<Botan::TLS::Session_Manager> m_client_sessions;
467
      std::shared_ptr<Botan::RandomNumberGenerator> m_rng;
468

469
      std::shared_ptr<Test_Callbacks> m_client_cb;
470

471
      std::shared_ptr<Test_Callbacks> m_server_cb;
472
      std::unique_ptr<Botan::TLS::Server> m_server;
473

474
      const bool m_client_auth;
475

476
      std::vector<uint8_t> m_c2s, m_s2c, m_client_recv, m_server_recv;
477
};
478

479
void TLS_Handshake_Test::go() {
128✔
480
   m_results.start_timer();
128✔
481

482
   Botan::RandomNumberGenerator& rng = Test::rng();
128✔
483

484
   const std::vector<std::string> protocols_offered = {"test/1", "test/2"};
384✔
485

486
   // Choose random application data to send
487
   const size_t c_len = 1 + ((static_cast<size_t>(rng.next_byte()) << 4) ^ rng.next_byte());
128✔
488
   std::vector<uint8_t> client_msg(c_len);
128✔
489
   Test::rng().randomize(client_msg.data(), client_msg.size());
128✔
490
   bool client_has_written = false;
128✔
491

492
   const size_t s_len = 1 + ((static_cast<size_t>(rng.next_byte()) << 4) ^ rng.next_byte());
128✔
493
   std::vector<uint8_t> server_msg(s_len);
128✔
494
   Test::rng().randomize(server_msg.data(), server_msg.size());
128✔
495
   bool server_has_written = false;
128✔
496

497
   std::unique_ptr<Botan::TLS::Client> client;
128✔
498
   client = std::make_unique<Botan::TLS::Client>(m_client_cb,
384✔
499
                                                 m_client_sessions,
128✔
500
                                                 m_creds,
128✔
501
                                                 m_client_policy,
128✔
502
                                                 m_rng,
128✔
503
                                                 Botan::TLS::Server_Information("server.example.com"),
256✔
504
                                                 m_offer_version,
128✔
505
                                                 protocols_offered);
128✔
506

507
   size_t rounds = 0;
128✔
508

509
   bool client_handshake_completed = false;
128✔
510
   bool server_handshake_completed = false;
128✔
511

512
   while(true) {
1,221✔
513
      ++rounds;
1,221✔
514

515
      if(rounds > 25) {
1,221✔
516
         m_results.test_failure("Still here after many rounds, deadlock?");
×
517
         break;
×
518
      }
519

520
      if(client_handshake_completed == false && client->is_active()) {
1,221✔
521
         client_handshake_completed = true;
522
      }
523

524
      if(server_handshake_completed == false && m_server->is_active()) {
1,221✔
525
         server_handshake_completed = true;
526
      }
527

528
      if(client->is_active() && client_has_written == false) {
1,221✔
529
         m_results.test_eq("client ALPN protocol", client->application_protocol(), "test/3");
232✔
530

531
         size_t sent_so_far = 0;
116✔
532
         while(sent_so_far != client_msg.size()) {
303✔
533
            const size_t left = client_msg.size() - sent_so_far;
187✔
534
            const size_t rnd12 = (rng.next_byte() << 4) ^ rng.next_byte();
187✔
535
            const size_t sending = std::min(left, rnd12);
187✔
536

537
            client->send(&client_msg[sent_so_far], sending);
187✔
538
            sent_so_far += sending;
187✔
539
         }
540
         client->send_warning_alert(Botan::TLS::Alert::NoRenegotiation);
116✔
541
         client_has_written = true;
542
      }
543

544
      if(m_server->is_active() && server_has_written == false) {
1,221✔
545
         m_results.test_eq("server ALPN protocol", m_server->application_protocol(), "test/3");
244✔
546

547
         size_t sent_so_far = 0;
122✔
548
         while(sent_so_far != server_msg.size()) {
348✔
549
            const size_t left = server_msg.size() - sent_so_far;
226✔
550
            const size_t rnd12 = (rng.next_byte() << 4) ^ rng.next_byte();
226✔
551
            const size_t sending = std::min(left, rnd12);
226✔
552

553
            m_server->send(&server_msg[sent_so_far], sending);
226✔
554
            sent_so_far += sending;
226✔
555
         }
556

557
         m_server->send_warning_alert(Botan::TLS::Alert::NoRenegotiation);
122✔
558
         server_has_written = true;
559
      }
560

561
      if(!m_c2s.empty()) {
1,221✔
562
         /*
563
         * Use this as a temp value to hold the queues as otherwise they
564
         * might end up appending more in response to messages during the
565
         * handshake.
566
         */
567
         std::vector<uint8_t> input;
543✔
568
         std::swap(m_c2s, input);
543✔
569

570
         try {
543✔
571
            size_t needed = m_server->received_data(input.data(), input.size());
543✔
572
            m_results.test_eq("full packet received", needed, 0);
1,074✔
573
         } catch(...) { /* ignore exceptions */
6✔
574
         }
6✔
575

576
         continue;
543✔
577
      }
543✔
578

579
      if(!m_s2c.empty()) {
678✔
580
         std::vector<uint8_t> input;
434✔
581
         std::swap(m_s2c, input);
434✔
582

583
         try {
434✔
584
            size_t needed = client->received_data(input.data(), input.size());
434✔
585
            m_results.test_eq("full packet received", needed, 0);
856✔
586
         } catch(...) { /* ignore exceptions */
6✔
587
         }
6✔
588

589
         continue;
434✔
590
      }
434✔
591

592
      if(!m_client_recv.empty()) {
244✔
593
         m_results.test_eq("client recv", m_client_recv, server_msg);
464✔
594
      }
595

596
      if(!m_server_recv.empty()) {
244✔
597
         m_results.test_eq("server recv", m_server_recv, client_msg);
464✔
598
      }
599

600
      if(client->is_closed() && m_server->is_closed()) {
244✔
601
         break;
602
      }
603

604
      if(m_server->is_active()) {
116✔
605
         std::vector<Botan::X509_Certificate> certs = m_server->peer_cert_chain();
116✔
606
         if(m_client_auth) {
116✔
607
            m_results.test_eq("got client certs", certs.size(), 2);
4✔
608

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

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

613
            for(const Botan::X509_DN& dn : acceptable_CAs) {
12✔
614
               m_results.test_eq("Expected CA country field", dn.get_first_attribute("C"), "VT");
16✔
615
            }
616
         } else {
4✔
617
            m_results.test_eq("no client certs", certs.size(), 0);
224✔
618
         }
619
      }
116✔
620

621
      if(!m_server_recv.empty() && !m_client_recv.empty()) {
116✔
622
         Botan::SymmetricKey client_key = client->key_material_export("label", "context", 32);
116✔
623
         Botan::SymmetricKey server_key = m_server->key_material_export("label", "context", 32);
116✔
624

625
         m_results.test_eq("TLS key material export", client_key.bits_of(), server_key.bits_of());
348✔
626

627
         m_results.confirm("Client is active", client->is_active());
232✔
628
         m_results.confirm("Client is not closed", !client->is_closed());
232✔
629
         client->close();
116✔
630
         m_results.confirm("Client is no longer active", !client->is_active());
232✔
631
         m_results.confirm("Client is closed", client->is_closed());
348✔
632
      }
232✔
633
   }
634

635
   m_results.end_timer();
128✔
636
}
384✔
637

638
class Test_Policy final : public Botan::TLS::Text_Policy {
29✔
639
   public:
640
      Test_Policy() : Text_Policy("") {}
29✔
641

642
      bool acceptable_protocol_version(Botan::TLS::Protocol_Version version) const override {
599✔
643
         // TODO: handle TLS 1.3 server once the time is ripe.
644
         return version.is_pre_tls_13();
599✔
645
      }
646

647
      size_t dtls_initial_timeout() const override { return 1; }
124✔
648

649
      size_t dtls_maximum_timeout() const override { return 8; }
124✔
650

651
      size_t minimum_rsa_bits() const override { return 1024; }
11✔
652

653
      size_t minimum_signature_strength() const override { return 80; }
98✔
654
};
655

656
class TLS_Unit_Tests final : public Test {
×
657
   private:
658
      static void test_with_policy(const std::string& test_descr,
30✔
659
                                   std::vector<Test::Result>& results,
660
                                   const std::shared_ptr<Botan::TLS::Session_Manager>& client_ses,
661
                                   const std::shared_ptr<Botan::TLS::Session_Manager>& server_ses,
662
                                   const std::shared_ptr<Credentials_Manager_Test>& creds,
663
                                   const std::vector<Botan::TLS::Protocol_Version>& versions,
664
                                   const std::shared_ptr<const Botan::TLS::Policy>& policy,
665
                                   bool client_auth = false) {
666
         auto rng = Test::rng_as_shared();
30✔
667

668
         try {
30✔
669
            for(const auto& version : versions) {
88✔
670
               TLS_Handshake_Test test(version.to_string() + " " + test_descr,
116✔
671
                                       version,
672
                                       creds,
673
                                       policy,
674
                                       policy,
675
                                       rng,
676
                                       client_ses,
677
                                       server_ses,
678
                                       client_auth);
116✔
679
               test.go();
58✔
680
               results.push_back(test.results());
58✔
681

682
               TLS_Handshake_Test test_resumption(version.to_string() + " " + test_descr,
116✔
683
                                                  version,
684
                                                  creds,
685
                                                  policy,
686
                                                  policy,
687
                                                  rng,
688
                                                  client_ses,
689
                                                  server_ses,
690
                                                  client_auth);
58✔
691
               test_resumption.go();
58✔
692
               results.push_back(test_resumption.results());
58✔
693
            }
58✔
694
         } catch(std::exception& e) { results.push_back(Test::Result::Failure(test_descr, e.what())); }
×
695
      }
30✔
696

697
      static void test_all_versions(const std::string& test_descr,
8✔
698
                                    std::vector<Test::Result>& results,
699
                                    const std::shared_ptr<Botan::TLS::Session_Manager>& client_ses,
700
                                    const std::shared_ptr<Botan::TLS::Session_Manager>& server_ses,
701
                                    const std::shared_ptr<Credentials_Manager_Test>& creds,
702
                                    const std::string& kex_policy,
703
                                    const std::string& cipher_policy,
704
                                    const std::string& mac_policy,
705
                                    const std::string& etm_policy,
706
                                    bool client_auth = false) {
707
         auto policy = std::make_shared<Test_Policy>();
8✔
708
         policy->set("ciphers", cipher_policy);
8✔
709
         policy->set("macs", mac_policy);
8✔
710
         policy->set("key_exchange_methods", kex_policy);
8✔
711
         policy->set("negotiate_encrypt_then_mac", etm_policy);
8✔
712

713
         policy->set("allow_tls12", "true");
16✔
714
         policy->set("allow_dtls12", "true");
16✔
715

716
         if(kex_policy.find("RSA") != std::string::npos) {
8✔
717
            policy->set("signature_methods", "IMPLICIT");
8✔
718
         }
719

720
         std::vector<Botan::TLS::Protocol_Version> versions = {Botan::TLS::Protocol_Version::TLS_V12,
8✔
721
                                                               Botan::TLS::Protocol_Version::DTLS_V12};
8✔
722

723
         return test_with_policy(test_descr, results, client_ses, server_ses, creds, versions, policy, client_auth);
16✔
724
      }
16✔
725

726
      static void test_modern_versions(const std::string& test_descr,
12✔
727
                                       std::vector<Test::Result>& results,
728
                                       const std::shared_ptr<Botan::TLS::Session_Manager>& client_ses,
729
                                       const std::shared_ptr<Botan::TLS::Session_Manager>& server_ses,
730
                                       const std::shared_ptr<Credentials_Manager_Test>& creds,
731
                                       const std::string& kex_policy,
732
                                       const std::string& cipher_policy,
733
                                       const std::string& mac_policy = "AEAD",
734
                                       bool client_auth = false) {
735
         std::map<std::string, std::string> no_extra_policies;
12✔
736
         return test_modern_versions(test_descr,
12✔
737
                                     results,
738
                                     client_ses,
739
                                     server_ses,
740
                                     creds,
741
                                     kex_policy,
742
                                     cipher_policy,
743
                                     mac_policy,
744
                                     no_extra_policies,
745
                                     client_auth);
12✔
746
      }
12✔
747

748
      static void test_modern_versions(const std::string& test_descr,
20✔
749
                                       std::vector<Test::Result>& results,
750
                                       const std::shared_ptr<Botan::TLS::Session_Manager>& client_ses,
751
                                       const std::shared_ptr<Botan::TLS::Session_Manager>& server_ses,
752
                                       const std::shared_ptr<Credentials_Manager_Test>& creds,
753
                                       const std::string& kex_policy,
754
                                       const std::string& cipher_policy,
755
                                       const std::string& mac_policy,
756
                                       const std::map<std::string, std::string>& extra_policies,
757
                                       bool client_auth = false) {
758
         auto policy = std::make_shared<Test_Policy>();
20✔
759
         policy->set("ciphers", cipher_policy);
20✔
760
         policy->set("macs", mac_policy);
20✔
761
         policy->set("key_exchange_methods", kex_policy);
20✔
762
         policy->set("allow_tls12", "true");
40✔
763
         policy->set("allow_dtls12", "true");
40✔
764

765
         if(kex_policy.find("RSA") != std::string::npos) {
20✔
766
            policy->set("signature_methods", "IMPLICIT");
2✔
767
         }
768

769
         for(const auto& kv : extra_policies) {
29✔
770
            policy->set(kv.first, kv.second);
9✔
771
         }
772

773
         std::vector<Botan::TLS::Protocol_Version> versions = {Botan::TLS::Protocol_Version::TLS_V12,
20✔
774
                                                               Botan::TLS::Protocol_Version::DTLS_V12};
20✔
775

776
         return test_with_policy(test_descr, results, client_ses, server_ses, creds, versions, policy, client_auth);
40✔
777
      }
40✔
778

779
      void test_session_established_abort(std::vector<Test::Result>& results,
1✔
780
                                          std::shared_ptr<Credentials_Manager_Test> creds,
781
                                          std::shared_ptr<Botan::RandomNumberGenerator> rng) {
782
         std::vector<Botan::TLS::Protocol_Version> versions = {Botan::TLS::Protocol_Version::TLS_V12,
1✔
783
                                                               Botan::TLS::Protocol_Version::DTLS_V12};
1✔
784

785
         auto policy = std::make_shared<Test_Policy>();
1✔
786
         auto noop_session_manager = std::make_shared<Botan::TLS::Session_Manager_Noop>();
1✔
787

788
         auto client_aborts = [&](const std::exception_ptr& ex, Botan::TLS::Alert expected_server_alert) {
4✔
789
            for(const auto version : versions) {
9✔
790
               TLS_Handshake_Test test("Client aborts in tls_session_established with " +
12✔
791
                                          expected_server_alert.type_string() + ": " + version.to_string(),
24✔
792
                                       version,
793
                                       creds,
6✔
794
                                       policy,
12✔
795
                                       policy,
796
                                       rng,
6✔
797
                                       noop_session_manager,
6✔
798
                                       noop_session_manager,
799
                                       false);
30✔
800
               test.set_custom_client_tls_session_established_callback(
12✔
801
                  [=](const auto&) { std::rethrow_exception(ex); });
36✔
802
               test.set_server_expected_handshake_alert(expected_server_alert);
6✔
803

804
               test.go();
6✔
805
               results.push_back(test.results());
6✔
806
            }
6✔
807
         };
3✔
808

809
         auto server_aborts = [&](const std::exception_ptr& ex, Botan::TLS::Alert expected_server_alert) {
4✔
810
            for(const auto version : versions) {
9✔
811
               TLS_Handshake_Test test("Server aborts in tls_session_established with " +
12✔
812
                                          expected_server_alert.type_string() + ": " + version.to_string(),
24✔
813
                                       version,
814
                                       creds,
6✔
815
                                       policy,
12✔
816
                                       policy,
817
                                       rng,
6✔
818
                                       noop_session_manager,
6✔
819
                                       noop_session_manager,
820
                                       false);
30✔
821
               test.set_custom_server_tls_session_established_callback(
12✔
822
                  [=](const auto&) { std::rethrow_exception(ex); });
36✔
823
               test.set_client_expected_handshake_alert(expected_server_alert);
6✔
824

825
               test.go();
6✔
826
               results.push_back(test.results());
6✔
827
            }
6✔
828
         };
3✔
829

830
         client_aborts(std::make_exception_ptr(
3✔
831
                          Botan::TLS::TLS_Exception(Botan::TLS::Alert::AccessDenied, "some test TLS exception")),
1✔
832
                       Botan::TLS::Alert::AccessDenied);
833
         client_aborts(std::make_exception_ptr(Botan::Invalid_Authentication_Tag("some symmetric crypto failed :o)")),
2✔
834
                       Botan::TLS::Alert::BadRecordMac);
835
         client_aborts(std::make_exception_ptr(std::runtime_error("something strange happened")),
2✔
836
                       Botan::TLS::Alert::InternalError);
837

838
         server_aborts(std::make_exception_ptr(
3✔
839
                          Botan::TLS::TLS_Exception(Botan::TLS::Alert::AccessDenied, "some server test TLS exception")),
1✔
840
                       Botan::TLS::Alert::AccessDenied);
841
         server_aborts(std::make_exception_ptr(
2✔
842
                          Botan::Invalid_Authentication_Tag("some symmetric crypto failed in the server :o)")),
1✔
843
                       Botan::TLS::Alert::BadRecordMac);
844
         server_aborts(std::make_exception_ptr(std::runtime_error("something strange happened in the server")),
2✔
845
                       Botan::TLS::Alert::InternalError);
846
      }
3✔
847

848
   public:
849
      std::vector<Test::Result> run() override {
1✔
850
         std::vector<Test::Result> results;
1✔
851

852
         auto rng = Test::rng_as_shared();
1✔
853

854
         std::shared_ptr<Botan::TLS::Session_Manager> client_ses;
1✔
855
         std::shared_ptr<Botan::TLS::Session_Manager> server_ses;
1✔
856

857
   #if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
858
         client_ses.reset(new Botan::TLS::Session_Manager_SQLite("client pass", rng, ":memory:", 5));
1✔
859
         server_ses.reset(new Botan::TLS::Session_Manager_SQLite("server pass", rng, ":memory:", 10));
1✔
860

861
   #else
862
         client_ses = std::make_shared<Botan::TLS::Session_Manager_In_Memory>(rng);
863
         server_ses = std::make_shared<Botan::TLS::Session_Manager_In_Memory>(rng);
864
   #endif
865

866
         auto creds = create_creds(*rng);
1✔
867

868
   #if defined(BOTAN_HAS_TLS_CBC)
869
         for(std::string etm_setting : {"false", "true"}) {
3✔
870
            test_all_versions(
4✔
871
               "AES-128 RSA", results, client_ses, server_ses, creds, "RSA", "AES-128", "SHA-256 SHA-1", etm_setting);
872
            test_all_versions(
4✔
873
               "AES-128 ECDH", results, client_ses, server_ses, creds, "ECDH", "AES-128", "SHA-256 SHA-1", etm_setting);
874

875
      #if defined(BOTAN_HAS_DES)
876
            test_all_versions("3DES RSA", results, client_ses, server_ses, creds, "RSA", "3DES", "SHA-1", etm_setting);
4✔
877
            test_all_versions(
4✔
878
               "3DES ECDH", results, client_ses, server_ses, creds, "ECDH", "3DES", "SHA-1", etm_setting);
879
      #endif
880

881
            server_ses->remove_all();
2✔
882
         }
2✔
883
         client_ses->remove_all();
1✔
884

885
         test_modern_versions("AES-128 DH", results, client_ses, server_ses, creds, "DH", "AES-128", "SHA-256");
2✔
886

887
   #endif
888

889
         auto strict_policy = std::make_shared<Botan::TLS::Strict_Policy_Without_TLS13>();
1✔
890
         test_with_policy("Strict policy",
3✔
891
                          results,
892
                          client_ses,
893
                          server_ses,
894
                          creds,
895
                          {Botan::TLS::Protocol_Version::TLS_V12},
896
                          strict_policy);
897

898
         auto suiteb_128 = std::make_shared<Botan::TLS::NSA_Suite_B_128>();
1✔
899
         test_with_policy(
3✔
900
            "Suite B", results, client_ses, server_ses, creds, {Botan::TLS::Protocol_Version::TLS_V12}, suiteb_128);
901

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

905
         test_modern_versions("AES-128/GCM RSA", results, client_ses, server_ses, creds, "RSA", "AES-128/GCM");
2✔
906
         test_modern_versions("AES-128/GCM ECDH", results, client_ses, server_ses, creds, "ECDH", "AES-128/GCM");
2✔
907

908
         test_modern_versions("AES-128/GCM ECDH RSA",
3✔
909
                              results,
910
                              client_ses,
911
                              server_ses,
912
                              creds,
913
                              "ECDH",
914
                              "AES-128/GCM",
915
                              "AEAD",
916
                              {{"signature_methods", "RSA"}});
917

918
         test_modern_versions("AES-128/GCM ECDH no OCSP",
3✔
919
                              results,
920
                              client_ses,
921
                              server_ses,
922
                              creds,
923
                              "ECDH",
924
                              "AES-128/GCM",
925
                              "AEAD",
926
                              {{"support_cert_status_message", "false"}});
927

928
         client_ses->remove_all();
1✔
929

930
   #if defined(BOTAN_HAS_CAMELLIA) && defined(BOTAN_HAS_AEAD_GCM)
931
         test_modern_versions(
3✔
932
            "Camellia-128/GCM ECDH", results, client_ses, server_ses, creds, "ECDH", "Camellia-128/GCM", "AEAD");
933
   #endif
934

935
   #if defined(BOTAN_HAS_ARIA)
936
         test_modern_versions("ARIA/GCM ECDH", results, client_ses, server_ses, creds, "ECDH", "ARIA-128/GCM", "AEAD");
2✔
937
   #endif
938

939
         test_modern_versions("AES-128/GCM point compression",
3✔
940
                              results,
941
                              client_ses,
942
                              server_ses,
943
                              creds,
944
                              "ECDH",
945
                              "AES-128/GCM",
946
                              "AEAD",
947
                              {{"use_ecc_point_compression", "true"}});
948
         test_modern_versions("AES-256/GCM p521",
3✔
949
                              results,
950
                              client_ses,
951
                              server_ses,
952
                              creds,
953
                              "ECDH",
954
                              "AES-256/GCM",
955
                              "AEAD",
956
                              {{"groups", "secp521r1"}});
957
         test_modern_versions("AES-128/GCM bp256r1",
3✔
958
                              results,
959
                              client_ses,
960
                              server_ses,
961
                              creds,
962
                              "ECDH",
963
                              "AES-128/GCM",
964
                              "AEAD",
965
                              {{"groups", "brainpool256r1"}});
966

967
   #if defined(BOTAN_HAS_CURVE_25519)
968
         test_modern_versions(
3✔
969
            "AES-128/GCM x25519", results, client_ses, server_ses, creds, "ECDH", "AES-128/GCM", "AEAD", {{
970
               "groups",
971
               "x25519"
972
            }});
973
   #endif
974

975
         test_modern_versions("AES-128/GCM FFDHE-2048",
3✔
976
                              results,
977
                              client_ses,
978
                              server_ses,
979
                              creds,
980
                              "DH",
981
                              "AES-128/GCM",
982
                              "AEAD",
983
                              {{"groups", "ffdhe/ietf/2048"}});
984

985
         auto creds_with_client_cert = create_creds(*rng, true);
1✔
986

987
         client_ses->remove_all();
1✔
988
         test_modern_versions("AES-256/GCM client certs",
2✔
989
                              results,
990
                              client_ses,
991
                              server_ses,
992
                              creds_with_client_cert,
993
                              "ECDH",
994
                              "AES-256/GCM",
995
                              "AEAD",
996
                              true);
997

998
   #if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
999
         client_ses.reset(new Botan::TLS::Session_Manager_In_Memory(rng));
1✔
1000
         server_ses.reset(new Botan::TLS::Session_Manager_In_Memory(rng));
1✔
1001
   #endif
1002

1003
   #if defined(BOTAN_HAS_AEAD_OCB)
1004
         test_modern_versions("AES-256/OCB ECDH", results, client_ses, server_ses, creds, "ECDH", "AES-256/OCB(12)");
2✔
1005
   #endif
1006

1007
         server_ses->remove_all();
1✔
1008

1009
   #if defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
1010
         test_modern_versions(
3✔
1011
            "ChaCha20Poly1305 ECDH", results, client_ses, server_ses, creds, "ECDH", "ChaCha20Poly1305");
1012
   #endif
1013

1014
         test_modern_versions("AES-128/GCM PSK", results, client_ses, server_ses, creds, "PSK", "AES-128/GCM");
2✔
1015

1016
   #if defined(BOTAN_HAS_AEAD_CCM)
1017
         test_modern_versions("AES-128/CCM PSK", results, client_ses, server_ses, creds, "PSK", "AES-128/CCM");
2✔
1018
         test_modern_versions("AES-128/CCM-8 PSK", results, client_ses, server_ses, creds, "PSK", "AES-128/CCM(8)");
2✔
1019
   #endif
1020

1021
         test_modern_versions(
2✔
1022
            "AES-128/GCM ECDHE_PSK", results, client_ses, server_ses, creds, "ECDHE_PSK", "AES-128/GCM");
1023

1024
         // Test with a custom curve
1025

1026
         /*
1027
         * First register a curve, in this case secp112r1
1028
         */
1029
         const Botan::BigInt p("0xDB7C2ABF62E35E668076BEAD208B");
1✔
1030
         const Botan::BigInt a("0xDB7C2ABF62E35E668076BEAD2088");
1✔
1031
         const Botan::BigInt b("0x659EF8BA043916EEDE8911702B22");
1✔
1032

1033
         const Botan::BigInt g_x("0x09487239995A5EE76B55F9C2F098");
1✔
1034
         const Botan::BigInt g_y("0xA89CE5AF8724C0A23E0E0FF77500");
1✔
1035
         const Botan::BigInt order("0xDB7C2ABF62E35E7628DFAC6561C5");
1✔
1036

1037
         const Botan::OID oid("1.3.132.0.6");
1✔
1038
         Botan::OID::register_oid(oid, "secp112r1");
1✔
1039

1040
         // Creating this object implicitly registers the curve for future use ...
1041
         Botan::EC_Group reg_secp112r1(p, a, b, g_x, g_y, order, 1, oid);
1✔
1042

1043
         test_modern_versions("AES-256/GCM secp112r1",
4✔
1044
                              results,
1045
                              client_ses,
1046
                              server_ses,
1047
                              creds,
1048
                              "ECDH",
1049
                              "AES-256/GCM",
1050
                              "AEAD",
1051
                              {{"groups", "0xFEE1"}, {"minimum_ecdh_group_size", "112"}});
1052

1053
         // Test connection abort by the application
1054
         // by throwing in Callbacks::tls_session_established()
1055

1056
         test_session_established_abort(results, creds, rng);
2✔
1057

1058
         return results;
2✔
1059
      }
14✔
1060
};
1061

1062
BOTAN_REGISTER_TEST("tls", "unit_tls", TLS_Unit_Tests);
1063

1064
class DTLS_Reconnection_Test : public Test {
×
1065
   public:
1066
      std::vector<Test::Result> run() override {
1✔
1067
         class Test_Callbacks : public Botan::TLS::Callbacks {
4✔
1068
            public:
1069
               Test_Callbacks(Test::Result& results, std::vector<uint8_t>& outbound, std::vector<uint8_t>& recv_buf) :
3✔
1070
                     m_results(results), m_outbound(outbound), m_recv(recv_buf) {}
3✔
1071

1072
               void tls_emit_data(std::span<const uint8_t> bits) override {
28✔
1073
                  m_outbound.insert(m_outbound.end(), bits.begin(), bits.end());
28✔
1074
               }
28✔
1075

1076
               void tls_record_received(uint64_t /*seq*/, std::span<const uint8_t> bits) override {
4✔
1077
                  m_recv.insert(m_recv.end(), bits.begin(), bits.end());
4✔
1078
               }
4✔
1079

1080
               void tls_alert(Botan::TLS::Alert /*alert*/) override {
×
1081
                  // ignore
1082
               }
×
1083

1084
               void tls_session_established(const Botan::TLS::Session_Summary& /*session*/) override {
4✔
1085
                  m_results.test_success("Established a session");
4✔
1086
               }
4✔
1087

1088
            private:
1089
               Test::Result& m_results;
1090
               std::vector<uint8_t>& m_outbound;
1091
               std::vector<uint8_t>& m_recv;
1092
         };
1093

1094
         class Credentials_PSK : public Botan::Credentials_Manager {
3✔
1095
            public:
1096
               Botan::SymmetricKey psk(const std::string& type,
8✔
1097
                                       const std::string& context,
1098
                                       const std::string& /*identity*/) override {
1099
                  if(type == "tls-server" && context == "session-ticket") {
8✔
1100
                     return Botan::SymmetricKey("AABBCCDDEEFF012345678012345678");
×
1101
                  }
1102

1103
                  if(type == "tls-server" && context == "dtls-cookie-secret") {
8✔
1104
                     return Botan::SymmetricKey("4AEA5EAD279CADEB537A594DA0E9DE3A");
4✔
1105
                  }
1106

1107
                  if(context == "localhost" && type == "tls-client") {
4✔
1108
                     return Botan::SymmetricKey("20B602D1475F2DF888FCB60D2AE03AFD");
2✔
1109
                  }
1110

1111
                  if(context == "localhost" && type == "tls-server") {
2✔
1112
                     return Botan::SymmetricKey("20B602D1475F2DF888FCB60D2AE03AFD");
2✔
1113
                  }
1114

1115
                  throw Test_Error("No PSK set for " + type + "/" + context);
×
1116
               }
1117
         };
1118

1119
         class Datagram_PSK_Policy : public Botan::TLS::Policy {
5✔
1120
            public:
1121
               std::vector<std::string> allowed_macs() const override { return std::vector<std::string>({"AEAD"}); }
216✔
1122

1123
               std::vector<std::string> allowed_key_exchange_methods() const override { return {"PSK"}; }
8✔
1124

1125
               bool allow_tls12() const override { return false; }
6✔
1126

1127
               bool allow_dtls12() const override { return true; }
19✔
1128

1129
               bool allow_dtls_epoch0_restart() const override { return true; }
8✔
1130
         };
1131

1132
         Test::Result result("DTLS reconnection");
1✔
1133

1134
         auto server_policy = std::make_shared<Datagram_PSK_Policy>();
1✔
1135
         auto client_policy = std::make_shared<Datagram_PSK_Policy>();
1✔
1136
         auto creds = std::make_shared<Credentials_PSK>();
1✔
1137
         auto server_sessions = std::make_shared<Botan::TLS::Session_Manager_In_Memory>(rng_as_shared());
2✔
1138
         auto client_sessions = std::make_shared<Botan::TLS::Session_Manager_Noop>();
1✔
1139

1140
         std::vector<uint8_t> s2c, server_recv;
1✔
1141
         auto server_callbacks = std::make_shared<Test_Callbacks>(result, s2c, server_recv);
1✔
1142
         Botan::TLS::Server server(server_callbacks, server_sessions, creds, server_policy, rng_as_shared(), true);
6✔
1143

1144
         std::vector<uint8_t> c1_c2s, client1_recv;
1✔
1145
         auto client1_callbacks = std::make_shared<Test_Callbacks>(result, c1_c2s, client1_recv);
1✔
1146
         Botan::TLS::Client client1(client1_callbacks,
1✔
1147
                                    client_sessions,
1148
                                    creds,
1149
                                    client_policy,
1150
                                    rng_as_shared(),
2✔
1151
                                    Botan::TLS::Server_Information("localhost"),
2✔
1152
                                    Botan::TLS::Protocol_Version::latest_dtls_version());
6✔
1153

1154
         bool c1_to_server_sent = false;
1✔
1155
         bool server_to_c1_sent = false;
1✔
1156

1157
         const std::vector<uint8_t> c1_to_server_magic(16, 0xC1);
1✔
1158
         const std::vector<uint8_t> server_to_c1_magic(16, 0x42);
1✔
1159

1160
         size_t c1_rounds = 0;
1✔
1161
         for(;;) {
10✔
1162
            c1_rounds++;
10✔
1163

1164
            if(c1_rounds > 64) {
10✔
1165
               result.test_failure("Still spinning in client1 loop after 64 rounds");
×
1166
               return {result};
×
1167
            }
1168

1169
            if(!c1_c2s.empty()) {
10✔
1170
               std::vector<uint8_t> input;
4✔
1171
               std::swap(c1_c2s, input);
4✔
1172
               server.received_data(input.data(), input.size());
4✔
1173
               continue;
4✔
1174
            }
4✔
1175

1176
            if(!s2c.empty()) {
6✔
1177
               std::vector<uint8_t> input;
4✔
1178
               std::swap(s2c, input);
4✔
1179
               client1.received_data(input.data(), input.size());
4✔
1180
               continue;
4✔
1181
            }
4✔
1182

1183
            if(!c1_to_server_sent && client1.is_active()) {
2✔
1184
               client1.send(c1_to_server_magic);
1✔
1185
               c1_to_server_sent = true;
1✔
1186
            }
1187

1188
            if(!server_to_c1_sent && server.is_active()) {
2✔
1189
               server.send(server_to_c1_magic);
2✔
1190
            }
1191

1192
            if(!server_recv.empty() && !client1_recv.empty()) {
2✔
1193
               result.test_eq("Expected message from client1", server_recv, c1_to_server_magic);
1✔
1194
               result.test_eq("Expected message to client1", client1_recv, server_to_c1_magic);
1✔
1195
               break;
1✔
1196
            }
1197
         }
1198

1199
         // Now client1 "goes away" (goes silent) and new client
1200
         // connects to same server context (ie due to reuse of client source port)
1201
         // See RFC 6347 section 4.2.8
1202

1203
         server_recv.clear();
1✔
1204
         s2c.clear();
1✔
1205

1206
         std::vector<uint8_t> c2_c2s, client2_recv;
1✔
1207
         auto client2_callbacks = std::make_shared<Test_Callbacks>(result, c2_c2s, client2_recv);
1✔
1208
         Botan::TLS::Client client2(client2_callbacks,
1✔
1209
                                    client_sessions,
1210
                                    creds,
1211
                                    client_policy,
1212
                                    rng_as_shared(),
2✔
1213
                                    Botan::TLS::Server_Information("localhost"),
2✔
1214
                                    Botan::TLS::Protocol_Version::latest_dtls_version());
6✔
1215

1216
         bool c2_to_server_sent = false;
1✔
1217
         bool server_to_c2_sent = false;
1✔
1218

1219
         const std::vector<uint8_t> c2_to_server_magic(16, 0xC2);
1✔
1220
         const std::vector<uint8_t> server_to_c2_magic(16, 0x66);
1✔
1221

1222
         size_t c2_rounds = 0;
1✔
1223

1224
         for(;;) {
10✔
1225
            c2_rounds++;
10✔
1226

1227
            if(c2_rounds > 64) {
10✔
1228
               result.test_failure("Still spinning in client2 loop after 64 rounds");
×
1229
               return {result};
×
1230
            }
1231

1232
            if(!c2_c2s.empty()) {
10✔
1233
               std::vector<uint8_t> input;
4✔
1234
               std::swap(c2_c2s, input);
4✔
1235
               server.received_data(input.data(), input.size());
4✔
1236
               continue;
4✔
1237
            }
4✔
1238

1239
            if(!s2c.empty()) {
6✔
1240
               std::vector<uint8_t> input;
4✔
1241
               std::swap(s2c, input);
4✔
1242
               client2.received_data(input.data(), input.size());
4✔
1243
               continue;
4✔
1244
            }
4✔
1245

1246
            if(!c2_to_server_sent && client2.is_active()) {
2✔
1247
               client2.send(c2_to_server_magic);
1✔
1248
               c2_to_server_sent = true;
1✔
1249
            }
1250

1251
            if(!server_to_c2_sent && server.is_active()) {
2✔
1252
               server.send(server_to_c2_magic);
2✔
1253
            }
1254

1255
            if(!server_recv.empty() && !client2_recv.empty()) {
2✔
1256
               result.test_eq("Expected message from client2", server_recv, c2_to_server_magic);
1✔
1257
               result.test_eq("Expected message to client2", client2_recv, server_to_c2_magic);
1✔
1258
               break;
1✔
1259
            }
1260
         }
1261

1262
         return {result};
2✔
1263
      }
17✔
1264
};
1265

1266
BOTAN_REGISTER_TEST("tls", "tls_dtls_reconnect", DTLS_Reconnection_Test);
1267

1268
#endif
1269

1270
}  // namespace
1271

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