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

randombit / botan / 4892192195

05 May 2023 10:32AM UTC coverage: 91.732% (+0.008%) from 91.724%
4892192195

push

github

77631 of 84628 relevant lines covered (91.73%)

11913034.27 hits per line

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

91.16
/src/tests/test_tls.cpp
1
/*
2
* (C) 2014,2015,2017,2018 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include "tests.h"
8
#include <memory>
9
#include <fstream>
10

11
#if defined(BOTAN_HAS_TLS)
12
  #include "test_rng.h"
13

14
  #include <botan/tls_alert.h>
15
  #include <botan/tls_policy.h>
16
  #include <botan/tls_session.h>
17
  #include <botan/tls_version.h>
18

19
  #if defined(BOTAN_HAS_TLS_CBC)
20
     #include <botan/internal/tls_cbc.h>
21
  #endif
22

23
#endif
24

25
namespace Botan_Tests {
26

27
#if defined(BOTAN_HAS_TLS)
28

29
class TLS_Session_Tests final : public Test
×
30
   {
31
   public:
32
      std::vector<Test::Result> run() override
1✔
33
         {
34
         Test::Result result("TLS::Session");
1✔
35

36
         Botan::TLS::Session session(Botan::secure_vector<uint8_t>{0xCC, 0xDD},
3✔
37
                                     Botan::TLS::Protocol_Version::TLS_V12,
38
                                     0xC02F,
39
                                     Botan::TLS::Connection_Side::Client,
40
                                     true,
41
                                     false,
42
                                     std::vector<Botan::X509_Certificate>(),
2✔
43
                                     Botan::TLS::Server_Information("server"),
1✔
44
                                     0x0000,
45
                                     std::chrono::system_clock::now());
2✔
46

47
         const std::string pem = session.PEM_encode();
1✔
48
         Botan::TLS::Session session_from_pem(pem);
1✔
49
         result.test_eq("Roundtrip from pem", session.DER_encode(), session_from_pem.DER_encode());
3✔
50

51
         const auto der = session.DER_encode();
1✔
52
         Botan::TLS::Session session_from_der(der);
1✔
53
         result.test_eq("Roundtrip from der", session.DER_encode(), session_from_der.DER_encode());
3✔
54

55
         const Botan::SymmetricKey key("ABCDEF");
1✔
56
         const std::vector<uint8_t> ctext1 = session.encrypt(key, Test::rng());
1✔
57
         const std::vector<uint8_t> ctext2 = session.encrypt(key, Test::rng());
1✔
58

59
         result.test_ne("TLS session encryption is non-determinsitic",
1✔
60
                        ctext1.data(), ctext1.size(),
61
                        ctext2.data(), ctext2.size());
62

63
         const std::vector<uint8_t> expected_hdr = Botan::hex_decode("068B5A9D396C0000F2322CAE");
1✔
64

65
         result.test_eq("tls", "TLS session encryption same header",
1✔
66
                        ctext1.data(), 12, expected_hdr.data(), 12);
67
         result.test_eq("tls", "TLS session encryption same header",
1✔
68
                        ctext2.data(), 12, expected_hdr.data(), 12);
69

70
         Botan::TLS::Session dsession = Botan::TLS::Session::decrypt(ctext1.data(), ctext1.size(), key);
1✔
71

72
         Fixed_Output_RNG frng1("00112233445566778899AABBCCDDEEFF802802802802802802802802");
1✔
73
         const std::vector<uint8_t> ctextf1 = session.encrypt(key, frng1);
1✔
74
         Fixed_Output_RNG frng2("00112233445566778899AABBCCDDEEFF802802802802802802802802");
1✔
75
         const std::vector<uint8_t> ctextf2 = session.encrypt(key, frng2);
1✔
76

77
         result.test_eq("Only randomness comes from RNG", ctextf1, ctextf2);
1✔
78

79
         Botan::TLS::Session session2(Botan::secure_vector<uint8_t>{0xCC, 0xEE},
3✔
80
                                     Botan::TLS::Protocol_Version::TLS_V12,
81
                                     0xBAAD, // cipher suite does not exist
82
                                     Botan::TLS::Connection_Side::Client,
83
                                     true,
84
                                     false,
85
                                     std::vector<Botan::X509_Certificate>(),
2✔
86
                                     Botan::TLS::Server_Information("server"),
1✔
87
                                     0x0000,
88
                                     std::chrono::system_clock::now());
2✔
89
         const std::string pem_with_unknown_ciphersuite = session2.PEM_encode();
1✔
90

91
         result.test_throws("unknown ciphersuite during session parsing",
3✔
92
                            "Serialized TLS session contains unknown cipher suite (47789)",
93
                            [&] { Botan::TLS::Session{pem_with_unknown_ciphersuite}; });
1✔
94

95
         return {result};
3✔
96
         }
9✔
97
   };
98

99
BOTAN_REGISTER_TEST("tls", "tls_session", TLS_Session_Tests);
100

101
#if defined(BOTAN_HAS_TLS_CBC)
102

103
class TLS_CBC_Padding_Tests final : public Text_Based_Test
×
104
   {
105
   public:
106
      TLS_CBC_Padding_Tests() : Text_Based_Test("tls_cbc_padding.vec", "Record,Output") {}
2✔
107

108
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override
22✔
109
         {
110
         const std::vector<uint8_t> record    = vars.get_req_bin("Record");
22✔
111
         const size_t output = vars.get_req_sz("Output");
22✔
112

113
         uint16_t res = Botan::TLS::check_tls_cbc_padding(record.data(), record.size());
22✔
114

115
         Test::Result result("TLS CBC padding check");
22✔
116
         result.test_eq("Expected", res, output);
22✔
117
         return result;
22✔
118
         }
22✔
119
   };
120

121
BOTAN_REGISTER_TEST("tls", "tls_cbc_padding", TLS_CBC_Padding_Tests);
122

123
class TLS_CBC_Tests final : public Text_Based_Test
×
124
   {
125
   public:
126

127
      class ZeroMac : public Botan::MessageAuthenticationCode
128
         {
129
         public:
130
            explicit ZeroMac(size_t mac_len) : m_mac_len(mac_len) {}
10✔
131

132
            void clear() override {}
×
133

134
            std::string name() const override { return "ZeroMac"; }
16✔
135
            size_t output_length() const override { return m_mac_len; }
10✔
136

137
            void add_data(const uint8_t /*input*/[], size_t /*length*/) override {}
26✔
138

139
            void final_result(uint8_t out[]) override
10✔
140
               {
141
               for(size_t i = 0; i != m_mac_len; ++i)
206✔
142
                  out[i] = 0;
196✔
143
               }
10✔
144

145
            bool has_keying_material() const override { return true; }
×
146

147
            Botan::Key_Length_Specification key_spec() const override
10✔
148
               {
149
               return Botan::Key_Length_Specification(0, 0, 1);
10✔
150
               }
151

152
            std::unique_ptr<MessageAuthenticationCode> new_object() const override
×
153
               {
154
               return std::make_unique<ZeroMac>(m_mac_len);
×
155
               }
156

157
         private:
158
            void key_schedule(const uint8_t /*key*/[], size_t /*length*/) override {}
10✔
159

160
            size_t m_mac_len;
161
         };
162

163
      class Noop_Block_Cipher : public Botan::BlockCipher
164
         {
165
         public:
166
            explicit Noop_Block_Cipher(size_t bs) : m_bs(bs) {}
10✔
167

168
            void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
×
169
               {
170
               Botan::copy_mem(out, in, blocks * m_bs);
×
171
               }
×
172

173
            void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
10✔
174
               {
175
               Botan::copy_mem(out, in, blocks * m_bs);
10✔
176
               }
10✔
177

178
            size_t block_size() const override { return m_bs; }
40✔
179
            void clear() override { }
×
180
            std::string name() const override { return "noop"; }
10✔
181

182
            bool has_keying_material() const override { return true; }
×
183

184
            Botan::Key_Length_Specification key_spec() const override
20✔
185
               {
186
               return Botan::Key_Length_Specification(0, 0, 1);
20✔
187
               }
188

189
            std::unique_ptr<BlockCipher> new_object() const override
×
190
               {
191
               return std::make_unique<Noop_Block_Cipher>(m_bs);
×
192
               }
193
         private:
194
            void key_schedule(const uint8_t /*key*/[], size_t /*length*/) override {}
10✔
195

196
            size_t m_bs;
197
         };
198

199
      TLS_CBC_Tests() : Text_Based_Test("tls_cbc.vec", "Blocksize,MACsize,Record,Valid") {}
3✔
200

201
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override
10✔
202
         {
203
         Test::Result result("TLS CBC");
10✔
204

205
         const size_t block_size = vars.get_req_sz("Blocksize");
10✔
206
         const size_t mac_len = vars.get_req_sz("MACsize");
10✔
207
         const std::vector<uint8_t> record = vars.get_req_bin("Record");
10✔
208
         const bool is_valid = vars.get_req_sz("Valid") == 1;
10✔
209

210
         // todo test permutations
211
         bool encrypt_then_mac = false;
10✔
212

213
         Botan::TLS::TLS_CBC_HMAC_AEAD_Decryption tls_cbc(
10✔
214
            std::make_unique<Noop_Block_Cipher>(block_size),
20✔
215
            std::make_unique<ZeroMac>(mac_len),
10✔
216
            0, 0, Botan::TLS::Protocol_Version::TLS_V12, encrypt_then_mac);
20✔
217

218
         tls_cbc.set_key(std::vector<uint8_t>(0));
20✔
219
         std::vector<uint8_t> ad(13);
10✔
220
         tls_cbc.set_associated_data(ad.data(), ad.size());
10✔
221

222
         Botan::secure_vector<uint8_t> vec(record.begin(), record.end());
10✔
223

224
         try
10✔
225
            {
226
            tls_cbc.finish(vec, 0);
10✔
227
            if(is_valid)
4✔
228
               result.test_success("Accepted valid TLS-CBC ciphertext");
8✔
229
            else
230
               result.test_failure("Accepted invalid TLS-CBC ciphertext");
×
231
            }
232
         catch(std::exception&)
6✔
233
            {
234
            if(is_valid)
6✔
235
               result.test_failure("Rejected valid TLS-CBC ciphertext");
×
236
            else
237
               result.test_success("Accepted invalid TLS-CBC ciphertext");
12✔
238
            }
6✔
239

240
         return result;
10✔
241
         }
30✔
242
   };
243

244
BOTAN_REGISTER_TEST("tls", "tls_cbc", TLS_CBC_Tests);
245

246
#endif
247

248
class Test_TLS_Alert_Strings : public Test
1✔
249
   {
250
   public:
251
      std::vector<Test::Result> run() override
1✔
252
         {
253
         Test::Result result("TLS::Alert::type_string");
1✔
254

255
         const std::vector<Botan::TLS::Alert::Type> alert_types =
1✔
256
            {
257
               Botan::TLS::Alert::CloseNotify,
258
               Botan::TLS::Alert::UnexpectedMessage,
259
               Botan::TLS::Alert::BadRecordMac,
260
               Botan::TLS::Alert::DecryptionFailed,
261
               Botan::TLS::Alert::RecordOverflow,
262
               Botan::TLS::Alert::DecompressionFailure,
263
               Botan::TLS::Alert::HandshakeFailure,
264
               Botan::TLS::Alert::NoCertificate,
265
               Botan::TLS::Alert::BadCertificate,
266
               Botan::TLS::Alert::UnsupportedCertificate,
267
               Botan::TLS::Alert::CertificateRevoked,
268
               Botan::TLS::Alert::CertificateExpired,
269
               Botan::TLS::Alert::CertificateUnknown,
270
               Botan::TLS::Alert::IllegalParameter,
271
               Botan::TLS::Alert::UnknownCA,
272
               Botan::TLS::Alert::AccessDenied,
273
               Botan::TLS::Alert::DecodeError,
274
               Botan::TLS::Alert::DecryptError,
275
               Botan::TLS::Alert::ExportRestriction,
276
               Botan::TLS::Alert::ProtocolVersion,
277
               Botan::TLS::Alert::InsufficientSecurity,
278
               Botan::TLS::Alert::InternalError,
279
               Botan::TLS::Alert::InappropriateFallback,
280
               Botan::TLS::Alert::UserCanceled,
281
               Botan::TLS::Alert::NoRenegotiation,
282
               Botan::TLS::Alert::MissingExtension,
283
               Botan::TLS::Alert::UnsupportedExtension,
284
               Botan::TLS::Alert::CertificateUnobtainable,
285
               Botan::TLS::Alert::UnrecognizedName,
286
               Botan::TLS::Alert::BadCertificateStatusResponse,
287
               Botan::TLS::Alert::BadCertificateHashValue,
288
               Botan::TLS::Alert::UnknownPSKIdentity,
289
               Botan::TLS::Alert::NoApplicationProtocol,
290
            };
1✔
291

292
         std::set<std::string> seen;
1✔
293

294
         for(auto alert : alert_types)
34✔
295
            {
296
            const std::string str = Botan::TLS::Alert(alert).type_string();
33✔
297
            result.test_eq("No duplicate strings", seen.count(str), 0);
33✔
298
            seen.insert(str);
33✔
299
            }
33✔
300

301
         Botan::TLS::Alert unknown_alert = Botan::TLS::Alert({01, 66});
1✔
302

303
         result.test_eq("Unknown alert str", unknown_alert.type_string(), "unrecognized_alert_66");
3✔
304

305
         return {result};
3✔
306
         }
2✔
307
   };
308

309
BOTAN_REGISTER_TEST("tls", "tls_alert_strings", Test_TLS_Alert_Strings);
310

311
class Test_TLS_Policy_Text : public Test
1✔
312
   {
313
   public:
314
      std::vector<Test::Result> run() override
1✔
315
         {
316
         Test::Result result("TLS Policy");
1✔
317

318
         const std::vector<std::string> policies = { "default", "suiteb_128", "suiteb_192", "strict", "datagram", "bsi" };
7✔
319

320
         for(const std::string& policy : policies)
7✔
321
            {
322
            const std::string from_policy_obj = tls_policy_string(policy);
6✔
323
            std::string from_file =
6✔
324
#if defined(BOTAN_HAS_TLS_13)
325
               read_tls_policy(policy + (policy == "default" || policy == "strict" ? "_tls13" : ""));
7✔
326
#else
327
               read_tls_policy(policy);
328
#endif
329

330
            result.test_eq("Values for TLS " + policy + " policy", from_file, from_policy_obj);
12✔
331
            }
12✔
332

333
         return {result};
3✔
334
         }
1✔
335

336
   private:
337
      static std::string read_tls_policy(const std::string& policy_str)
6✔
338
         {
339
         const std::string fspath = Test::data_file("tls-policy/" + policy_str + ".txt");
12✔
340

341
         std::ifstream is(fspath.c_str());
6✔
342
         if(!is.good())
6✔
343
            {
344
            throw Test_Error("Missing policy file " + fspath);
×
345
            }
346

347
         Botan::TLS::Text_Policy policy(is);
6✔
348
         return policy.to_string();
6✔
349
         }
12✔
350

351
      static std::string tls_policy_string(const std::string& policy_str)
6✔
352
         {
353
         std::unique_ptr<Botan::TLS::Policy> policy;
6✔
354
         if(policy_str == "default")
6✔
355
            {
356
            policy = std::make_unique<Botan::TLS::Policy>();
1✔
357
            }
358
         else if(policy_str == "suiteb_128")
5✔
359
            {
360
            policy = std::make_unique<Botan::TLS::NSA_Suite_B_128>();
1✔
361
            }
362
         else if(policy_str == "suiteb_192")
4✔
363
            {
364
            policy = std::make_unique<Botan::TLS::NSA_Suite_B_192>();
1✔
365
            }
366
         else if(policy_str == "bsi")
3✔
367
            {
368
            policy = std::make_unique<Botan::TLS::BSI_TR_02102_2>();
1✔
369
            }
370
         else if(policy_str == "strict")
2✔
371
            {
372
            policy = std::make_unique<Botan::TLS::Strict_Policy>();
1✔
373
            }
374
         else if(policy_str == "datagram")
1✔
375
            {
376
            policy = std::make_unique<Botan::TLS::Datagram_Policy>();
1✔
377
            }
378
         else
379
            {
380
            throw Test_Error("Unknown TLS policy type '" + policy_str + "'");
×
381
            }
382

383
         return policy->to_string();
6✔
384
         }
6✔
385
   };
386

387
BOTAN_REGISTER_TEST("tls", "tls_policy_text", Test_TLS_Policy_Text);
388

389
class Test_TLS_Ciphersuites : public Test
1✔
390
   {
391
   public:
392
      std::vector<Test::Result> run() override
1✔
393
         {
394
         Test::Result result("TLS::Ciphersuite");
1✔
395

396
         for(size_t csuite_id = 0; csuite_id <= 0xFFFF; ++csuite_id)
65,537✔
397
            {
398
            const uint16_t csuite_id16 = static_cast<uint16_t>(csuite_id);
65,536✔
399
            auto ciphersuite = Botan::TLS::Ciphersuite::by_id(csuite_id16);
65,536✔
400

401
            if(ciphersuite && ciphersuite->valid())
65,536✔
402
               {
403
               result.test_eq("Valid Ciphersuite is not SCSV", Botan::TLS::Ciphersuite::is_scsv(csuite_id16), false);
94✔
404

405
               if(ciphersuite->cbc_ciphersuite() == false)
94✔
406
                  {
407
                  result.test_eq("Expected AEAD ciphersuite", ciphersuite->aead_ciphersuite(), true);
64✔
408
                  result.test_eq("Expected MAC name for AEAD ciphersuites", ciphersuite->mac_algo(), "AEAD");
128✔
409
                  }
410
               else
411
                  {
412
                  result.test_eq("Did not expect AEAD ciphersuite", ciphersuite->aead_ciphersuite(), false);
30✔
413
                  result.test_eq("MAC algo and PRF algo same for CBC suites", ciphersuite->prf_algo(), ciphersuite->mac_algo());
60✔
414
                  }
415

416
               // TODO more tests here
417
               }
418
            }
419

420
         return {result};
3✔
421
         }
1✔
422
   };
423

424
BOTAN_REGISTER_TEST("tls", "tls_ciphersuites", Test_TLS_Ciphersuites);
425

426
class Test_TLS_Algo_Strings : public Test
1✔
427
   {
428
   public:
429

430
      std::vector<Test::Result> run() override
1✔
431
         {
432
         std::vector<Test::Result> results;
1✔
433

434
         results.push_back(test_auth_method_strings());
2✔
435
         results.push_back(test_kex_algo_strings());
2✔
436
         results.push_back(test_tls_sig_method_strings());
2✔
437

438
         return results;
1✔
439
         }
×
440

441
   private:
442
      static Test::Result test_tls_sig_method_strings()
1✔
443
         {
444
         Test::Result result("TLS::Signature_Scheme");
1✔
445

446
         std::vector<Botan::TLS::Signature_Scheme> schemes = Botan::TLS::Signature_Scheme::all_available_schemes();
1✔
447

448
         std::set<std::string> scheme_strs;
1✔
449
         for(auto scheme : schemes)
10✔
450
            {
451
            std::string scheme_str = scheme.to_string();
9✔
452

453
            result.test_eq("Scheme strings unique", scheme_strs.count(scheme_str), 0);
9✔
454

455
            scheme_strs.insert(scheme_str);
9✔
456
            }
9✔
457

458
         return result;
1✔
459
         }
2✔
460

461
      static Test::Result test_auth_method_strings()
1✔
462
         {
463
         Test::Result result("TLS::Auth_Method");
1✔
464

465
         const std::vector<Botan::TLS::Auth_Method> auth_methods({
1✔
466
            Botan::TLS::Auth_Method::RSA,
467
            Botan::TLS::Auth_Method::ECDSA,
468
            Botan::TLS::Auth_Method::IMPLICIT,
469
            });
1✔
470

471
         for(Botan::TLS::Auth_Method meth : auth_methods)
4✔
472
            {
473
            std::string meth_str = Botan::TLS::auth_method_to_string(meth);
3✔
474
            result.test_ne("Method string is not empty", meth_str, "");
6✔
475
            Botan::TLS::Auth_Method meth2 = Botan::TLS::auth_method_from_string(meth_str);
3✔
476
            result.confirm("Decoded method matches", meth == meth2);
9✔
477
            }
3✔
478

479
         return result;
1✔
480
         }
1✔
481

482
      static Test::Result test_kex_algo_strings()
1✔
483
         {
484
         Test::Result result("TLS::Kex_Algo");
1✔
485

486
         const std::vector<Botan::TLS::Kex_Algo> kex_algos({
1✔
487
            Botan::TLS::Kex_Algo::STATIC_RSA,
488
            Botan::TLS::Kex_Algo::DH,
489
            Botan::TLS::Kex_Algo::ECDH,
490
            Botan::TLS::Kex_Algo::PSK,
491
            Botan::TLS::Kex_Algo::ECDHE_PSK
492
            });
1✔
493

494
         for(Botan::TLS::Kex_Algo meth : kex_algos)
6✔
495
            {
496
            std::string meth_str = Botan::TLS::kex_method_to_string(meth);
5✔
497
            result.test_ne("Method string is not empty", meth_str, "");
10✔
498
            Botan::TLS::Kex_Algo meth2 = Botan::TLS::kex_method_from_string(meth_str);
5✔
499
            result.confirm("Decoded method matches", meth == meth2);
15✔
500
            }
5✔
501

502
         return result;
1✔
503
         }
1✔
504

505
   };
506

507
BOTAN_REGISTER_TEST("tls", "tls_algo_strings", Test_TLS_Algo_Strings);
508

509
#endif
510

511
}
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