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

randombit / botan / 25139258422

29 Apr 2026 08:02PM UTC coverage: 89.37% (-0.02%) from 89.385%
25139258422

push

github

web-flow
Merge pull request #5550 from randombit/jack/tls-misc

TLS conformance, hardening, and performance fixes

107055 of 119789 relevant lines covered (89.37%)

11415549.66 hits per line

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

88.28
/src/tests/test_tls_messages.cpp
1
/*
2
* (C) 2016 Juraj Somorovsky
3
* (C) 2021 Elektrobit Automotive GmbH
4
* (C) 2022 Hannes Rantzsch, René Meusel - neXenio GmbH
5
* (C) 2022 René Meusel - Rohde & Schwarz Cybersecurity
6
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9

10
#include "tests.h"
11

12
#if defined(BOTAN_HAS_TLS)
13
   #include <botan/mac.h>
14
   #include <botan/ocsp.h>
15
   #include <botan/tls_alert.h>
16
   #include <botan/tls_callbacks.h>
17
   #include <botan/tls_ciphersuite.h>
18
   #include <botan/tls_policy.h>
19
   #include <botan/tls_version.h>
20
   #include <botan/internal/loadstor.h>
21
   #include <algorithm>
22
   #include <exception>
23

24
   #if defined(BOTAN_HAS_TLS_12)
25
      #include <botan/tls_messages_12.h>
26
   #endif
27

28
   #if defined(BOTAN_HAS_TLS_13)
29
      #include "test_rng.h"
30
      #include <botan/tls_extensions_13.h>
31
      #include <botan/tls_messages_13.h>
32
      #include <botan/internal/tls_reader.h>
33
   #endif
34
#endif
35

36
namespace Botan_Tests {
37

38
namespace {
39

40
#if defined(BOTAN_HAS_TLS)
41

42
   #if defined(BOTAN_HAS_TLS_12)
43
Test::Result test_hello_verify_request() {
2✔
44
   Test::Result result("hello_verify_request construction");
2✔
45

46
   const std::vector<uint8_t> test_data;
2✔
47
   std::vector<uint8_t> key_data(32);
2✔
48
   const Botan::SymmetricKey sk(key_data);
2✔
49

50
   // Compute cookie over an empty string with an empty test data
51
   const Botan::TLS::Hello_Verify_Request hfr(test_data, "", sk);
2✔
52

53
   // Compute HMAC
54
   auto hmac = Botan::MessageAuthenticationCode::create("HMAC(SHA-256)");
2✔
55
   hmac->set_key(sk);
2✔
56
   hmac->update_be(uint64_t(0));  // length of client hello
2✔
57
   hmac->update_be(uint64_t(0));  // length of client identity
2✔
58
   std::vector<uint8_t> test = hmac->final<std::vector<uint8_t>>();
2✔
59

60
   result.test_bin_eq("Cookie comparison", hfr.cookie(), test);
2✔
61
   return result;
2✔
62
}
10✔
63
   #endif
64

65
class Test_Callbacks : public Botan::TLS::Callbacks {
11✔
66
   public:
67
      explicit Test_Callbacks(Test::Result& result) : m_result(result) {}
11✔
68

69
   public:
70
      void tls_emit_data(std::span<const uint8_t> /*data*/) override {
×
71
         m_result.test_failure("unsolicited call to tls_emit_data");
×
72
      }
×
73

74
      void tls_record_received(uint64_t /*rec_no*/, std::span<const uint8_t> /*data*/) override {
×
75
         m_result.test_failure("unsolicited call to tls_record_received");
×
76
      }
×
77

78
      void tls_alert(Botan::TLS::Alert /*alert*/) override { m_result.test_failure("unsolicited call to tls_alert"); }
×
79

80
      void tls_session_established(const Botan::TLS::Session_Summary& /*session_info*/) override {
×
81
         m_result.test_failure("unsolicited call to tls_session_established");
×
82
      }
×
83

84
   private:
85
      Test::Result& m_result;
86
};
87

88
   #if defined(BOTAN_HAS_TLS_12)
89
class TLS_Message_Parsing_Test final : public Text_Based_Test {
×
90
   public:
91
      TLS_Message_Parsing_Test() :
1✔
92
            Text_Based_Test("tls", "Buffer,Exception", "Protocol,AdditionalData,Ciphersuite,Name") {}
2✔
93

94
      Test::Result run_one_test(const std::string& algo, const VarMap& vars) override {
46✔
95
         const std::vector<uint8_t> buffer = vars.get_req_bin("Buffer");
46✔
96
         const std::vector<uint8_t> protocol = vars.get_opt_bin("Protocol");
46✔
97
         const std::vector<uint8_t> ciphersuite = vars.get_opt_bin("Ciphersuite");
46✔
98
         const std::string exception = vars.get_req_str("Exception");
46✔
99
         const std::string expected_name = vars.get_opt_str("Name", "");
46✔
100
         const bool is_positive_test = exception.empty();
46✔
101

102
         Test::Result result(algo + " parsing");
46✔
103

104
         if(is_positive_test) {
46✔
105
            try {
17✔
106
               if(algo == "cert_verify") {
17✔
107
                  const Botan::TLS::Certificate_Verify message(buffer);
2✔
108
               } else if(algo == "client_hello") {
17✔
109
                  const std::string extensions = vars.get_req_str("AdditionalData");
4✔
110
                  const Botan::TLS::Protocol_Version pv(protocol[0], protocol[1]);
4✔
111
                  const Botan::TLS::Client_Hello_12 message(buffer);
4✔
112
                  result.test_str_eq("Protocol version", message.legacy_version().to_string(), pv.to_string());
4✔
113
                  std::vector<uint8_t> buf;
4✔
114
                  for(const Botan::TLS::Extension_Code& type : message.extension_types()) {
28✔
115
                     const uint16_t u16type = static_cast<uint16_t>(type);
24✔
116
                     buf.push_back(Botan::get_byte<0>(u16type));
24✔
117
                     buf.push_back(Botan::get_byte<1>(u16type));
24✔
118
                  }
×
119
                  result.test_bin_eq("Hello extensions", buf, extensions);
4✔
120
               } else if(algo == "hello_verify") {
15✔
121
                  const Botan::TLS::Hello_Verify_Request message(buffer);
1✔
122
               } else if(algo == "hello_request") {
11✔
123
                  const Botan::TLS::Hello_Request message(buffer);
1✔
124
               } else if(algo == "new_session_ticket") {
10✔
125
                  const Botan::TLS::New_Session_Ticket_12 message(buffer);
3✔
126
               } else if(algo == "server_hello") {
9✔
127
                  const std::string extensions = vars.get_req_str("AdditionalData");
2✔
128
                  const Botan::TLS::Protocol_Version pv(protocol[0], protocol[1]);
2✔
129
                  const Botan::TLS::Ciphersuite cs =
2✔
130
                     Botan::TLS::Ciphersuite::by_id(Botan::make_uint16(ciphersuite[0], ciphersuite[1])).value();
2✔
131
                  const Botan::TLS::Server_Hello_12 message(buffer);
2✔
132
                  result.test_str_eq("Protocol version", message.legacy_version().to_string(), pv.to_string());
2✔
133
                  result.test_is_true("Ciphersuite", (message.ciphersuite() == cs.ciphersuite_code()));
2✔
134
                  std::vector<uint8_t> buf;
2✔
135
                  for(const Botan::TLS::Extension_Code& type : message.extension_types()) {
11✔
136
                     const uint16_t u16type = static_cast<uint16_t>(type);
9✔
137
                     buf.push_back(Botan::get_byte<0>(u16type));
9✔
138
                     buf.push_back(Botan::get_byte<1>(u16type));
9✔
139
                  }
×
140
                  result.test_bin_eq("Hello extensions", buf, extensions);
2✔
141
               } else if(algo == "alert") {
6✔
142
                  const Botan::secure_vector<uint8_t> sb(buffer.begin(), buffer.end());
3✔
143
                  const Botan::TLS::Alert message(sb);
3✔
144
                  result.test_sz_lt(
3✔
145
                     "Alert type vectors result to UNKNOWN_CA or ACCESS_DENIED, which is shorter than 15",
146
                     message.type_string().size(),
6✔
147
                     15);
148
               } else if(algo == "cert_status") {
4✔
149
                  const Botan::TLS::Certificate_Status message(buffer, Botan::TLS::Connection_Side::Server);
1✔
150

151
                  const Botan::OCSP::Response resp(message.response());
1✔
152

153
                  const std::vector<std::string> CNs = resp.signer_name().get_attribute("CN");
1✔
154

155
                  // This is not required by OCSP protocol, we are just using it as a test here
156
                  if(result.test_sz_eq("OCSP response has signer name", CNs.size(), 1)) {
1✔
157
                     result.test_str_eq("Expected name", CNs[0], expected_name);
1✔
158
                  }
159
               } else {
2✔
160
                  throw Test_Error("Unknown message type " + algo + " in TLS parsing tests");
×
161
               }
162
               result.test_success("Correct parsing");
17✔
163
            } catch(std::exception& e) {
×
164
               result.test_failure(e.what());
×
165
            }
×
166
         } else {
167
            if(algo == "cert_verify") {
29✔
168
               result.test_throws("invalid cert_verify input", exception, [&buffer]() {
2✔
169
                  const Botan::TLS::Certificate_Verify message(buffer);
2✔
170
               });
×
171
            } else if(algo == "client_hello") {
27✔
172
               result.test_throws("invalid client_hello input", exception, [&buffer]() {
9✔
173
                  const Botan::TLS::Client_Hello_12 message(buffer);
9✔
174
               });
×
175
            } else if(algo == "hello_verify") {
18✔
176
               result.test_throws("invalid hello_verify input", exception, [&buffer]() {
4✔
177
                  const Botan::TLS::Hello_Verify_Request message(buffer);
4✔
178
               });
×
179
            } else if(algo == "hello_request") {
14✔
180
               result.test_throws("invalid hello_request input", exception, [&buffer]() {
1✔
181
                  const Botan::TLS::Hello_Request message(buffer);
1✔
182
               });
×
183
            } else if(algo == "cert_status") {
13✔
184
               result.test_throws("invalid cert_status input", exception, [&buffer]() {
4✔
185
                  const Botan::TLS::Certificate_Status message(buffer, Botan::TLS::Connection_Side::Server);
4✔
186
               });
×
187
            } else if(algo == "new_session_ticket") {
9✔
188
               result.test_throws("invalid new_session_ticket input", exception, [&buffer]() {
2✔
189
                  const Botan::TLS::New_Session_Ticket_12 message(buffer);
2✔
190
               });
×
191
            } else if(algo == "server_hello") {
7✔
192
               result.test_throws("invalid server_hello input", exception, [&buffer]() {
4✔
193
                  const Botan::TLS::Server_Hello_12 message(buffer);
4✔
194
               });
×
195
            } else if(algo == "alert") {
3✔
196
               result.test_throws("invalid alert input", exception, [&buffer]() {
3✔
197
                  const Botan::secure_vector<uint8_t> sb(buffer.begin(), buffer.end());
3✔
198
                  const Botan::TLS::Alert message(sb);
3✔
199
               });
×
200
            } else {
201
               throw Test_Error("Unknown message type " + algo + " in TLS parsing tests");
×
202
            }
203
         }
204

205
         return result;
46✔
206
      }
118✔
207

208
      std::vector<Test::Result> run_final_tests() override {
1✔
209
         std::vector<Test::Result> results;
1✔
210

211
         results.push_back(test_hello_verify_request());
2✔
212

213
         return results;
1✔
214
      }
×
215
};
216

217
BOTAN_REGISTER_TEST("tls", "tls_messages", TLS_Message_Parsing_Test);
218
   #endif
219

220
   #if defined(BOTAN_HAS_TLS_13)
221
      #if defined(BOTAN_HAS_X25519)
222
class TLS_Key_Share_CH_Generation_Test final : public Text_Based_Test {
×
223
   public:
224
      TLS_Key_Share_CH_Generation_Test() :
1✔
225
            Text_Based_Test("tls_extensions/generation/key_share_CH_offers.vec",
226
                            "Groups,Rng_Data,Expected_Content",
227
                            "Offered_Groups") {}
2✔
228

229
      Test::Result run_one_test(const std::string& extension, const VarMap& vars) override {
11✔
230
         Test::Result result(extension + " generation");
11✔
231

232
         const auto rng_data = vars.get_req_bin("Rng_Data");
11✔
233
         const auto groups = vars.get_req_str("Groups");
11✔
234
         const auto offered_groups = vars.get_opt_str("Offered_Groups", groups);
11✔
235
         const auto expected_key_share = vars.get_req_bin("Expected_Content");
11✔
236

237
         Test_Callbacks cb(result);
11✔
238
         const Botan::TLS::Text_Policy policy("key_exchange_groups = " + groups +
22✔
239
                                              "\n"
240
                                              "key_exchange_groups_to_offer = " +
22✔
241
                                              offered_groups);
11✔
242
         Fixed_Output_RNG rng;
11✔
243
         rng.add_entropy(rng_data.data(), rng_data.size());
11✔
244

245
         const Botan::TLS::Key_Share share(policy, cb, rng);
11✔
246
         const auto serialized_buffer = share.serialize(Botan::TLS::Connection_Side::Client);
11✔
247

248
         result.test_bin_eq("key_share_CH_offers test", serialized_buffer, expected_key_share);
11✔
249

250
         return result;
11✔
251
      }
54✔
252
};
253

254
BOTAN_REGISTER_TEST("tls_extensions", "tls_extensions_key_share_client_hello", TLS_Key_Share_CH_Generation_Test);
255

256
      #endif
257

258
class TLS_Extension_Parsing_Test final : public Text_Based_Test {
×
259
   public:
260
      TLS_Extension_Parsing_Test() :
1✔
261
            Text_Based_Test("tls_extensions/parsing",
262
                            "Buffer,Exception",
263
                            "Protocol,Ciphersuite,AdditionalData,Name,Expected_Content") {}
2✔
264

265
      Test::Result run_one_test(const std::string& extension, const VarMap& vars) override {
35✔
266
         const std::vector<uint8_t> buffer = vars.get_req_bin("Buffer");
35✔
267
         const std::string exception = vars.get_req_str("Exception");
35✔
268
         const bool is_positive_test = exception.empty();
35✔
269

270
         Test::Result result(extension + " parsing");
35✔
271

272
         if(is_positive_test) {
35✔
273
            try {
14✔
274
               if(extension == "supported_version") {
14✔
275
                  Botan::TLS::TLS_Data_Reader tls_data_reader("ClientHello", buffer);
2✔
276
                  const Botan::TLS::Supported_Versions supported_versions(
2✔
277
                     tls_data_reader, static_cast<uint16_t>(buffer.size()), Botan::TLS::Connection_Side::Client);
2✔
278
                  const auto serialized_buffer = supported_versions.serialize(Botan::TLS::Connection_Side::Client);
2✔
279

280
                  const std::vector<std::vector<uint8_t>> expected_versions = vars.get_req_bin_list("Expected_Content");
2✔
281
                  for(const auto& expected_version : expected_versions) {
5✔
282
                     result.test_is_true("Expected_Content",
3✔
283
                                         supported_versions.supports(
3✔
284
                                            Botan::TLS::Protocol_Version(expected_version[0], expected_version[1])));
3✔
285
                  }
286

287
                  result.test_bin_eq("supported_version test 1", serialized_buffer, buffer);
2✔
288
               } else if(extension == "supported_groups") {
16✔
289
                  Botan::TLS::TLS_Data_Reader tls_data_reader("ClientHello", buffer);
2✔
290
                  const Botan::TLS::Supported_Groups supp_groups_ext(tls_data_reader,
2✔
291
                                                                     static_cast<uint16_t>(buffer.size()));
2✔
292

293
                  const auto serialized_buffer = supp_groups_ext.serialize(Botan::TLS::Connection_Side::Client);
2✔
294
                  const auto expected_content = vars.get_req_bin("Expected_Content");
2✔
295

296
                  const auto dh_groups = supp_groups_ext.dh_groups();
2✔
297
                  const auto ec_groups = supp_groups_ext.ec_groups();
2✔
298

299
                  std::vector<Botan::TLS::Named_Group> named_groups;
2✔
300
                  std::merge(dh_groups.begin(),
2✔
301
                             dh_groups.end(),
302
                             ec_groups.begin(),
303
                             ec_groups.end(),
304
                             std::back_inserter(named_groups));
305

306
                  result.test_is_true("supported_groups extension - size check",
2✔
307
                                      (named_groups.size() * 2) == expected_content.size());
2✔
308

309
                  for(size_t i = 0; i < expected_content.size(); i += 2) {
12✔
310
                     const auto expected_named_group =
10✔
311
                        Botan::make_uint16(expected_content.at(i), expected_content.at(i + 1));
10✔
312

313
                     result.test_is_true(
10✔
314
                        "signature_algorithms_cert extension - named group check",
315
                        std::any_of(named_groups.cbegin(),
10✔
316
                                    named_groups.cend(),
317
                                    [&expected_named_group](const Botan::TLS::Named_Group& named_group) {
46✔
318
                                       return static_cast<Botan::TLS::Named_Group>(expected_named_group) == named_group;
16✔
319
                                    }));
320
                  }
321

322
                  result.test_bin_eq("supported_groups extension - serialization test", serialized_buffer, buffer);
2✔
323
               } else if(extension == "signature_algorithms_cert") {
19✔
324
                  Botan::TLS::TLS_Data_Reader tls_data_reader("ClientHello", buffer);
2✔
325
                  const Botan::TLS::Signature_Algorithms_Cert sig_algo_cert(tls_data_reader,
2✔
326
                                                                            static_cast<uint16_t>(buffer.size()));
2✔
327

328
                  const auto serialized_buffer = sig_algo_cert.serialize(Botan::TLS::Connection_Side::Client);
2✔
329
                  const auto expected_content = vars.get_req_bin("Expected_Content");
2✔
330

331
                  result.test_is_true("signature_algorithms_cert extension - size check",
4✔
332
                                      sig_algo_cert.supported_schemes().size() * 2 == expected_content.size());
2✔
333

334
                  size_t offset = 0;
2✔
335
                  for(const auto& sig_scheme : sig_algo_cert.supported_schemes()) {
10✔
336
                     const auto expected_sig_scheme =
8✔
337
                        Botan::make_uint16(expected_content.at(offset), expected_content.at(offset + 1));
8✔
338

339
                     result.test_is_true("signature_algorithms_cert extension - sig scheme check",
24✔
340
                                         Botan::TLS::Signature_Scheme(expected_sig_scheme) == sig_scheme);
8✔
341

342
                     offset += 2;
8✔
343
                  }
344

345
                  result.test_bin_eq(
2✔
346
                     "signature_algorithms_cert extension - serialization test", serialized_buffer, buffer);
347
               } else if(extension == "cookie") {
12✔
348
                  Botan::TLS::TLS_Data_Reader tls_data_reader("HelloRetryRequest", buffer);
2✔
349
                  const Botan::TLS::Cookie cookie(tls_data_reader, static_cast<uint16_t>(buffer.size()));
2✔
350

351
                  const auto serialized_buffer = cookie.serialize(Botan::TLS::Connection_Side::Server);
2✔
352
                  const auto expected_cookie = vars.get_req_bin("Expected_Content");
2✔
353

354
                  result.test_bin_eq("Cookie extension test", expected_cookie, cookie.get_cookie());
2✔
355
               } else if(extension == "key_share_HRR") {
12✔
356
                  Botan::TLS::TLS_Data_Reader tls_data_reader("HelloRetryRequest", buffer);
1✔
357
                  const Botan::TLS::Key_Share key_share(tls_data_reader,
1✔
358
                                                        static_cast<uint16_t>(buffer.size()),
1✔
359
                                                        Botan::TLS::Handshake_Type::HelloRetryRequest);
1✔
360

361
                  const auto serialized_buffer = key_share.serialize(Botan::TLS::Connection_Side::Client);
1✔
362
                  const auto expected_key_share = vars.get_req_bin("Expected_Content");
1✔
363

364
                  result.test_bin_eq("key_share_HRR test", serialized_buffer, expected_key_share);
1✔
365
               } else if(extension == "key_share_SH") {
7✔
366
                  Botan::TLS::TLS_Data_Reader tls_data_reader("ServerHello", buffer);
1✔
367
                  const Botan::TLS::Key_Share key_share(
1✔
368
                     tls_data_reader, static_cast<uint16_t>(buffer.size()), Botan::TLS::Handshake_Type::ServerHello);
1✔
369

370
                  const auto serialized_buffer = key_share.serialize(Botan::TLS::Connection_Side::Client);
1✔
371
                  const auto expected_key_share = vars.get_req_bin("Expected_Content");
1✔
372

373
                  result.test_bin_eq("key_share_SH test", serialized_buffer, expected_key_share);
1✔
374
               } else if(extension == "key_share_CH") {
6✔
375
                  Botan::TLS::TLS_Data_Reader tls_data_reader("ClientHello", buffer);
2✔
376
                  const Botan::TLS::Key_Share key_share(
2✔
377
                     tls_data_reader, static_cast<uint16_t>(buffer.size()), Botan::TLS::Handshake_Type::ClientHello);
2✔
378

379
                  const auto serialized_buffer = key_share.serialize(Botan::TLS::Connection_Side::Server);
2✔
380
                  const auto expected_key_share = vars.get_req_bin("Expected_Content");
2✔
381

382
                  result.test_bin_eq("key_share_CH test", serialized_buffer, expected_key_share);
2✔
383
               } else if(extension == "alpn") {
6✔
384
                  Botan::TLS::TLS_Data_Reader tls_data_reader("ClientHello", buffer);
2✔
385
                  const Botan::TLS::Application_Layer_Protocol_Notification alpn(
2✔
386
                     tls_data_reader, static_cast<uint16_t>(buffer.size()), Botan::TLS::Connection_Side::Client);
2✔
387

388
                  std::string protocols_joined;
2✔
389
                  for(const auto& p : alpn.protocols()) {
5✔
390
                     if(!protocols_joined.empty()) {
3✔
391
                        protocols_joined.push_back(',');
1✔
392
                     }
393
                     protocols_joined += p;
6✔
394
                  }
395
                  result.test_str_eq("alpn protocols", protocols_joined, vars.get_req_str("Expected_Content"));
2✔
396
               } else {
2✔
397
                  throw Test_Error("Unknown extension type " + extension + " in TLS parsing tests");
×
398
               }
399
               result.test_success("Correct parsing");
14✔
400
            } catch(std::exception& e) {
×
401
               result.test_failure(e.what());
×
402
            }
×
403
         } else {
404
            if(extension == "cookie") {
21✔
405
               result.test_throws("invalid cookie extension input", exception, [&buffer]() {
6✔
406
                  Botan::TLS::TLS_Data_Reader tls_data_reader("HelloRetryRequest", buffer);
6✔
407
                  const Botan::TLS::Cookie cookie(tls_data_reader, static_cast<uint16_t>(buffer.size()));
6✔
408
               });
×
409
            } else if(extension == "supported_groups") {
15✔
410
               result.test_throws("invalid supported_groups extension input", exception, [&buffer]() {
4✔
411
                  Botan::TLS::TLS_Data_Reader tls_data_reader("ClientHello", buffer);
4✔
412
                  const Botan::TLS::Supported_Groups supp_groups_ext(tls_data_reader,
4✔
413
                                                                     static_cast<uint16_t>(buffer.size()));
4✔
414
               });
×
415
            } else if(extension == "key_share_CH") {
11✔
416
               result.test_throws("invalid key_share_CH extension input", exception, [&buffer]() {
2✔
417
                  Botan::TLS::TLS_Data_Reader tls_data_reader("ClientHello", buffer);
2✔
418
                  const Botan::TLS::Key_Share key_share(
2✔
419
                     tls_data_reader, static_cast<uint16_t>(buffer.size()), Botan::TLS::Handshake_Type::ClientHello);
2✔
420
               });
×
421
            } else if(extension == "key_share_HRR") {
9✔
422
               result.test_throws("invalid key_share_HRR extension input", exception, [&buffer]() {
1✔
423
                  Botan::TLS::TLS_Data_Reader tls_data_reader("HelloRetryRequest", buffer);
1✔
424
                  const Botan::TLS::Key_Share key_share(tls_data_reader,
1✔
425
                                                        static_cast<uint16_t>(buffer.size()),
1✔
426
                                                        Botan::TLS::Handshake_Type::HelloRetryRequest);
1✔
427
               });
×
428
            } else if(extension == "key_share_SH") {
8✔
429
               result.test_throws("invalid key_share_SH extension input", exception, [&buffer]() {
1✔
430
                  Botan::TLS::TLS_Data_Reader tls_data_reader("ServerHello", buffer);
1✔
431
                  const Botan::TLS::Key_Share key_share(
1✔
432
                     tls_data_reader, static_cast<uint16_t>(buffer.size()), Botan::TLS::Handshake_Type::ServerHello);
1✔
433
               });
×
434
            } else if(extension == "signature_algorithms_cert") {
7✔
435
               result.test_throws("invalid signature_algorithms_cert extension input", exception, [&buffer]() {
3✔
436
                  Botan::TLS::TLS_Data_Reader tls_data_reader("Extension", buffer);
3✔
437
                  const Botan::TLS::Signature_Algorithms_Cert sig_algo_cert(tls_data_reader,
3✔
438
                                                                            static_cast<uint16_t>(buffer.size()));
3✔
439
               });
×
440
            } else if(extension == "alpn") {
4✔
441
               result.test_throws("invalid alpn extension input", exception, [&buffer]() {
4✔
442
                  Botan::TLS::TLS_Data_Reader tls_data_reader("ClientHello", buffer);
4✔
443
                  const Botan::TLS::Application_Layer_Protocol_Notification alpn(
4✔
444
                     tls_data_reader, static_cast<uint16_t>(buffer.size()), Botan::TLS::Connection_Side::Client);
4✔
445
               });
×
446
            } else {
447
               throw Test_Error("Unknown extension type " + extension + " in TLS parsing negative tests");
×
448
            }
449
         }
450

451
         return result;
35✔
452
      }
70✔
453

454
      std::vector<Test::Result> run_final_tests() override {
1✔
455
         std::vector<Test::Result> results;
1✔
456

457
      #if defined(BOTAN_HAS_TLS_12)
458
         results.push_back(test_hello_verify_request());
2✔
459
      #endif
460

461
         return results;
1✔
462
      }
×
463
};
464

465
BOTAN_REGISTER_TEST("tls_extensions", "tls_extensions_parsing", TLS_Extension_Parsing_Test);
466

467
class TLS_13_Message_Parsing_Test final : public Text_Based_Test {
×
468
   public:
469
      TLS_13_Message_Parsing_Test() :
1✔
470
            Text_Based_Test("tls_13", "Buffer,Exception", "Protocol,Message_Type,AdditionalData,Ciphersuite,Name") {}
2✔
471

472
      Test::Result run_one_test(const std::string& algo, const VarMap& vars) override {
24✔
473
         const std::vector<uint8_t> buffer = vars.get_req_bin("Buffer");
24✔
474
         const std::vector<uint8_t> protocol = vars.get_opt_bin("Protocol");
24✔
475
         const std::string msg_type = vars.get_opt_str("Message_Type", "");
24✔
476
         const std::vector<uint8_t> ciphersuite = vars.get_opt_bin("Ciphersuite");
24✔
477
         const std::string exception = vars.get_req_str("Exception");
24✔
478
         const bool is_positive_test = exception.empty();
24✔
479

480
         Test::Result result("TLS 1.3 " + algo + " parsing");
72✔
481

482
         if(algo == "client_hello") {
24✔
483
            try {
16✔
484
               std::visit(
20✔
485
                  [&](auto ch) {
8✔
486
                     if constexpr(std::is_same_v<Botan::TLS::Client_Hello_12_Shim, decltype(ch)>) {
487
                        result.test_is_true("expected Client_Hello_12_Shim", msg_type == "client_hello_12");
3✔
488
                     }
489
                     if constexpr(std::is_same_v<Botan::TLS::Client_Hello_13, decltype(ch)>) {
490
                        result.test_is_true("expected Client_Hello_13", msg_type == "client_hello_13");
1✔
491
                     }
492

493
                     const std::string extensions = vars.get_req_str("AdditionalData");
4✔
494
                     std::vector<uint8_t> exts_buffer;
4✔
495
                     for(const Botan::TLS::Extension_Code& type : ch.extensions().extension_types()) {
25✔
496
                        const uint16_t u16type = static_cast<uint16_t>(type);
21✔
497
                        exts_buffer.push_back(Botan::get_byte<0>(u16type));
21✔
498
                        exts_buffer.push_back(Botan::get_byte<1>(u16type));
21✔
499
                     }
500
                     result.test_bin_eq("Hello extensions", exts_buffer, extensions);
4✔
501

502
                     std::vector<uint8_t> ciphersuites_buffer;
4✔
503
                     for(const auto& cs : ch.ciphersuites()) {
290✔
504
                        ciphersuites_buffer.push_back(Botan::get_byte<0>(cs));
286✔
505
                        ciphersuites_buffer.push_back(Botan::get_byte<1>(cs));
286✔
506
                     }
507
                     result.test_bin_eq("Supported ciphersuites", ciphersuites_buffer, ciphersuite);
4✔
508

509
                     result.test_is_true("this is a positive test that should not have failed yet", is_positive_test);
4✔
510
                  },
7✔
511
                  Botan::TLS::Client_Hello_13::parse(buffer));
20✔
512
            } catch(const std::exception& ex) {
12✔
513
               result.test_str_eq("correct error produced", ex.what(), exception);
12✔
514
               result.test_is_true("negative test", !is_positive_test);
12✔
515
            }
12✔
516
         }
517

518
         if(algo == "server_hello") {
24✔
519
            const std::string extensions = vars.get_req_str("AdditionalData");
8✔
520
            const Botan::TLS::Ciphersuite cs =
8✔
521
               Botan::TLS::Ciphersuite::by_id(Botan::make_uint16(ciphersuite[0], ciphersuite[1])).value();
8✔
522
            const Botan::TLS::Protocol_Version pv(protocol[0], protocol[1]);
8✔
523

524
            try {
8✔
525
               std::visit(
12✔
526
                  [&](auto msg) {
8✔
527
                     if constexpr(std::is_same_v<Botan::TLS::Server_Hello_12_Shim, decltype(msg)>) {
528
                        result.test_is_true("expected Server_Hello_12", msg_type == "server_hello_12");
2✔
529
                        result.test_is_true("expected pre TLS 1.3 message", pv == msg.selected_version());
2✔
530
                     } else if constexpr(std::is_same_v<Botan::TLS::Server_Hello_13, decltype(msg)>) {
531
                        result.test_is_true("expected Server_Hello_13", msg_type == "server_hello_13");
1✔
532
                     } else if constexpr(std::is_same_v<Botan::TLS::Hello_Retry_Request, decltype(msg)>) {
533
                        result.test_is_true("expected Hello_Retry_Request", msg_type == "hello_retry_request");
1✔
534
                     }
535

536
                     result.test_is_true("Ciphersuite", (msg.ciphersuite() == cs.ciphersuite_code()));
4✔
537

538
                     std::vector<uint8_t> buf;
4✔
539
                     for(const Botan::TLS::Extension_Code& type : msg.extensions().extension_types()) {
18✔
540
                        const uint16_t u16type = static_cast<uint16_t>(type);
14✔
541
                        buf.push_back(Botan::get_byte<0>(u16type));
14✔
542
                        buf.push_back(Botan::get_byte<1>(u16type));
14✔
543
                     }
544
                     result.test_bin_eq("Hello extensions", buf, extensions);
4✔
545
                  },
4✔
546
                  Botan::TLS::Server_Hello_13::parse(buffer));
12✔
547
            } catch(const std::exception& ex) {
4✔
548
               result.test_str_eq("correct error produced", ex.what(), exception);
4✔
549
               result.test_is_true("negative test", !is_positive_test);
4✔
550
            }
4✔
551
         }
8✔
552

553
         return result;
24✔
554
      }
87✔
555
};
556

557
BOTAN_REGISTER_TEST("tls", "tls_13_messages", TLS_13_Message_Parsing_Test);
558

559
   #endif
560

561
#endif
562

563
}  // namespace
564

565
}  // namespace Botan_Tests
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc