Coverage Report

Created: 2022-06-23 06:44

/src/botan/build/include/botan/tls_extensions.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
* TLS Extensions
3
* (C) 2011,2012,2016,2018,2019 Jack Lloyd
4
* (C) 2016 Juraj Somorovsky
5
* (C) 2016 Matthias Gierlings
6
* (C) 2021 Elektrobit Automotive GmbH
7
* (C) 2022 René Meusel, Hannes Rantzsch - neXenio GmbH
8
*
9
* Botan is released under the Simplified BSD License (see license.txt)
10
*/
11
12
#ifndef BOTAN_TLS_EXTENSIONS_H_
13
#define BOTAN_TLS_EXTENSIONS_H_
14
15
#include <botan/tls_algos.h>
16
#include <botan/tls_magic.h>
17
#include <botan/tls_version.h>
18
#include <botan/secmem.h>
19
#include <botan/pkix_types.h>
20
21
#include <algorithm>
22
#include <optional>
23
#include <variant>
24
#include <vector>
25
#include <string>
26
#include <set>
27
28
namespace Botan {
29
30
class RandomNumberGenerator;
31
32
namespace TLS {
33
34
class Policy;
35
class TLS_Data_Reader;
36
37
// This will become an enum class in a future major release
38
enum Handshake_Extension_Type {
39
   TLSEXT_SERVER_NAME_INDICATION    = 0,
40
   TLSEXT_CERT_STATUS_REQUEST       = 5,
41
42
   TLSEXT_CERTIFICATE_TYPES         = 9,
43
   TLSEXT_SUPPORTED_GROUPS          = 10,
44
   TLSEXT_EC_POINT_FORMATS          = 11,
45
   TLSEXT_SIGNATURE_ALGORITHMS      = 13,
46
   TLSEXT_USE_SRTP                  = 14,
47
   TLSEXT_ALPN                      = 16,
48
49
   TLSEXT_ENCRYPT_THEN_MAC          = 22,
50
   TLSEXT_EXTENDED_MASTER_SECRET    = 23,
51
52
   TLSEXT_SESSION_TICKET            = 35,
53
54
   TLSEXT_SUPPORTED_VERSIONS        = 43,
55
56
   TLSEXT_SAFE_RENEGOTIATION     = 65281,
57
};
58
59
/**
60
* Base class representing a TLS extension of some kind
61
*/
62
class BOTAN_UNSTABLE_API Extension
63
   {
64
   public:
65
      /**
66
      * @return code number of the extension
67
      */
68
      virtual Handshake_Extension_Type type() const = 0;
69
70
      /**
71
      * @return serialized binary for the extension
72
      */
73
      virtual std::vector<uint8_t> serialize(Connection_Side whoami) const = 0;
74
75
      /**
76
      * @return if we should encode this extension or not
77
      */
78
      virtual bool empty() const = 0;
79
80
      /**
81
       * @return true if this extension is known and implemented by Botan
82
       */
83
0
      virtual bool is_implemented() const { return true; }
84
85
221k
      virtual ~Extension() = default;
86
   };
87
88
/**
89
* Server Name Indicator extension (RFC 3546)
90
*/
91
class BOTAN_UNSTABLE_API Server_Name_Indicator final : public Extension
92
   {
93
   public:
94
      static Handshake_Extension_Type static_type()
95
129k
         { return TLSEXT_SERVER_NAME_INDICATION; }
96
97
75.1k
      Handshake_Extension_Type type() const override { return static_type(); }
98
99
      explicit Server_Name_Indicator(const std::string& host_name) :
100
1.42k
         m_sni_host_name(host_name) {}
101
102
      Server_Name_Indicator(TLS_Data_Reader& reader,
103
                            uint16_t extension_size);
104
105
6.43k
      std::string host_name() const { return m_sni_host_name; }
106
107
      std::vector<uint8_t> serialize(Connection_Side whoami) const override;
108
109
1.42k
      bool empty() const override { return m_sni_host_name.empty(); }
110
   private:
111
      std::string m_sni_host_name;
112
   };
113
114
/**
115
* Renegotiation Indication Extension (RFC 5746)
116
*/
117
class BOTAN_UNSTABLE_API Renegotiation_Extension final : public Extension
118
   {
119
   public:
120
      static Handshake_Extension_Type static_type()
121
323k
         { return TLSEXT_SAFE_RENEGOTIATION; }
122
123
227k
      Handshake_Extension_Type type() const override { return static_type(); }
124
125
11.2k
      Renegotiation_Extension() = default;
126
127
      explicit Renegotiation_Extension(const std::vector<uint8_t>& bits) :
128
12.5k
         m_reneg_data(bits) {}
129
130
      Renegotiation_Extension(TLS_Data_Reader& reader,
131
                             uint16_t extension_size);
132
133
      const std::vector<uint8_t>& renegotiation_info() const
134
23.7k
         { return m_reneg_data; }
135
136
      std::vector<uint8_t> serialize(Connection_Side whoami) const override;
137
138
12.5k
      bool empty() const override { return false; } // always send this
139
   private:
140
      std::vector<uint8_t> m_reneg_data;
141
   };
142
143
/**
144
* ALPN (RFC 7301)
145
*/
146
class BOTAN_UNSTABLE_API Application_Layer_Protocol_Notification final : public Extension
147
   {
148
   public:
149
121k
      static Handshake_Extension_Type static_type() { return TLSEXT_ALPN; }
150
151
94.7k
      Handshake_Extension_Type type() const override { return static_type(); }
152
153
3.42k
      const std::vector<std::string>& protocols() const { return m_protocols; }
154
155
      const std::string& single_protocol() const;
156
157
      /**
158
      * Single protocol, used by server
159
      */
160
      explicit Application_Layer_Protocol_Notification(const std::string& protocol) :
161
3.39k
         m_protocols(1, protocol) {}
162
163
      /**
164
      * List of protocols, used by client
165
      */
166
      explicit Application_Layer_Protocol_Notification(const std::vector<std::string>& protocols) :
167
0
         m_protocols(protocols) {}
168
169
      Application_Layer_Protocol_Notification(TLS_Data_Reader& reader,
170
                                              uint16_t extension_size,
171
                                              Connection_Side from);
172
173
      std::vector<uint8_t> serialize(Connection_Side whoami) const override;
174
175
3.39k
      bool empty() const override { return m_protocols.empty(); }
176
   private:
177
      std::vector<std::string> m_protocols;
178
   };
179
180
/**
181
* Session Ticket Extension (RFC 5077)
182
*/
183
class BOTAN_UNSTABLE_API Session_Ticket final : public Extension
184
   {
185
   public:
186
      static Handshake_Extension_Type static_type()
187
178k
         { return TLSEXT_SESSION_TICKET; }
188
189
138k
      Handshake_Extension_Type type() const override { return static_type(); }
190
191
      /**
192
      * @return contents of the session ticket
193
      */
194
6.68k
      const std::vector<uint8_t>& contents() const { return m_ticket; }
195
196
      /**
197
      * Create empty extension, used by both client and server
198
      */
199
8.05k
      Session_Ticket() = default;
200
201
      /**
202
      * Extension with ticket, used by client
203
      */
204
      explicit Session_Ticket(const std::vector<uint8_t>& session_ticket) :
205
0
         m_ticket(session_ticket) {}
206
207
      /**
208
      * Deserialize a session ticket
209
      */
210
      Session_Ticket(TLS_Data_Reader& reader, uint16_t extension_size);
211
212
8.05k
      std::vector<uint8_t> serialize(Connection_Side) const override { return m_ticket; }
213
214
8.05k
      bool empty() const override { return false; }
215
   private:
216
      std::vector<uint8_t> m_ticket;
217
   };
218
219
220
/**
221
* Supported Groups Extension (RFC 7919)
222
*/
223
class BOTAN_UNSTABLE_API Supported_Groups final : public Extension
224
   {
225
   public:
226
      static Handshake_Extension_Type static_type()
227
559k
         { return TLSEXT_SUPPORTED_GROUPS; }
228
229
520k
      Handshake_Extension_Type type() const override { return static_type(); }
230
231
      const std::vector<Group_Params>& groups() const;
232
      std::vector<Group_Params> ec_groups() const;
233
      std::vector<Group_Params> dh_groups() const;
234
235
      std::vector<uint8_t> serialize(Connection_Side whoami) const override;
236
237
      explicit Supported_Groups(const std::vector<Group_Params>& groups);
238
239
      Supported_Groups(TLS_Data_Reader& reader,
240
                       uint16_t extension_size);
241
242
1.42k
      bool empty() const override { return m_groups.empty(); }
243
   private:
244
      std::vector<Group_Params> m_groups;
245
   };
246
247
// previously Supported Elliptic Curves Extension (RFC 4492)
248
//using Supported_Elliptic_Curves = Supported_Groups;
249
250
/**
251
* Supported Point Formats Extension (RFC 4492)
252
*/
253
class BOTAN_UNSTABLE_API Supported_Point_Formats final : public Extension
254
   {
255
   public:
256
      enum ECPointFormat : uint8_t {
257
         UNCOMPRESSED = 0,
258
         ANSIX962_COMPRESSED_PRIME = 1,
259
         ANSIX962_COMPRESSED_CHAR2 = 2, // don't support these curves
260
      };
261
262
      static Handshake_Extension_Type static_type()
263
130k
         { return TLSEXT_EC_POINT_FORMATS; }
264
265
112k
      Handshake_Extension_Type type() const override { return static_type(); }
266
267
      std::vector<uint8_t> serialize(Connection_Side whoami) const override;
268
269
      explicit Supported_Point_Formats(bool prefer_compressed) :
270
4.93k
         m_prefers_compressed(prefer_compressed) {}
271
272
      Supported_Point_Formats(TLS_Data_Reader& reader,
273
                              uint16_t extension_size);
274
275
4.93k
      bool empty() const override { return false; }
276
277
3.50k
      bool prefers_compressed() { return m_prefers_compressed; }
278
279
   private:
280
      bool m_prefers_compressed = false;
281
   };
282
283
/**
284
* Signature Algorithms Extension for TLS 1.2 (RFC 5246)
285
*/
286
class BOTAN_UNSTABLE_API Signature_Algorithms final : public Extension
287
   {
288
   public:
289
      static Handshake_Extension_Type static_type()
290
4.84k
         { return TLSEXT_SIGNATURE_ALGORITHMS; }
291
292
4.75k
      Handshake_Extension_Type type() const override { return static_type(); }
293
294
69
      const std::vector<Signature_Scheme>& supported_schemes() const { return m_schemes; }
295
296
      std::vector<uint8_t> serialize(Connection_Side whoami) const override;
297
298
1.42k
      bool empty() const override { return m_schemes.empty(); }
299
300
      explicit Signature_Algorithms(const std::vector<Signature_Scheme>& schemes) :
301
1.42k
         m_schemes(schemes) {}
302
303
      Signature_Algorithms(TLS_Data_Reader& reader,
304
                           uint16_t extension_size);
305
   private:
306
      std::vector<Signature_Scheme> m_schemes;
307
   };
308
309
/**
310
* Used to indicate SRTP algorithms for DTLS (RFC 5764)
311
*/
312
class BOTAN_UNSTABLE_API SRTP_Protection_Profiles final : public Extension
313
   {
314
   public:
315
      static Handshake_Extension_Type static_type()
316
1.36k
         { return TLSEXT_USE_SRTP; }
317
318
1.05k
      Handshake_Extension_Type type() const override { return static_type(); }
319
320
0
      const std::vector<uint16_t>& profiles() const { return m_pp; }
321
322
      std::vector<uint8_t> serialize(Connection_Side whoami) const override;
323
324
0
      bool empty() const override { return m_pp.empty(); }
325
326
0
      explicit SRTP_Protection_Profiles(const std::vector<uint16_t>& pp) : m_pp(pp) {}
327
328
0
      explicit SRTP_Protection_Profiles(uint16_t pp) : m_pp(1, pp) {}
329
330
      SRTP_Protection_Profiles(TLS_Data_Reader& reader, uint16_t extension_size);
331
   private:
332
      std::vector<uint16_t> m_pp;
333
   };
334
335
/**
336
* Extended Master Secret Extension (RFC 7627)
337
*/
338
class BOTAN_UNSTABLE_API Extended_Master_Secret final : public Extension
339
   {
340
   public:
341
      static Handshake_Extension_Type static_type()
342
82.0k
         { return TLSEXT_EXTENDED_MASTER_SECRET; }
343
344
48.4k
      Handshake_Extension_Type type() const override { return static_type(); }
345
346
      std::vector<uint8_t> serialize(Connection_Side whoami) const override;
347
348
2.31k
      bool empty() const override { return false; }
349
350
2.31k
      Extended_Master_Secret() = default;
351
352
      Extended_Master_Secret(TLS_Data_Reader& reader, uint16_t extension_size);
353
   };
354
355
/**
356
* Encrypt-then-MAC Extension (RFC 7366)
357
*/
358
class BOTAN_UNSTABLE_API Encrypt_then_MAC final : public Extension
359
   {
360
   public:
361
      static Handshake_Extension_Type static_type()
362
133k
         { return TLSEXT_ENCRYPT_THEN_MAC; }
363
364
117k
      Handshake_Extension_Type type() const override { return static_type(); }
365
366
      std::vector<uint8_t> serialize(Connection_Side whoami) const override;
367
368
3.87k
      bool empty() const override { return false; }
369
370
3.87k
      Encrypt_then_MAC() = default;
371
372
      Encrypt_then_MAC(TLS_Data_Reader& reader, uint16_t extension_size);
373
   };
374
375
/**
376
* Certificate Status Request (RFC 6066)
377
*/
378
class BOTAN_UNSTABLE_API Certificate_Status_Request final : public Extension
379
   {
380
   public:
381
      static Handshake_Extension_Type static_type()
382
101k
         { return TLSEXT_CERT_STATUS_REQUEST; }
383
384
81.5k
      Handshake_Extension_Type type() const override { return static_type(); }
385
386
      std::vector<uint8_t> serialize(Connection_Side whoami) const override;
387
388
3.45k
      bool empty() const override { return false; }
389
390
      const std::vector<uint8_t>& get_responder_id_list() const
391
0
         {
392
0
         return m_ocsp_names;
393
0
         }
394
395
      const std::vector<uint8_t>& get_request_extensions() const
396
0
         {
397
0
         return m_extension_bytes;
398
0
         }
399
400
      const std::vector<uint8_t>& get_ocsp_response() const
401
0
         {
402
0
         return m_response;
403
0
         }
404
405
      // Server generated version: empty
406
2.02k
      Certificate_Status_Request() {}
407
408
      // Client version, both lists can be empty
409
      Certificate_Status_Request(const std::vector<uint8_t>& ocsp_responder_ids,
410
                                 const std::vector<std::vector<uint8_t>>& ocsp_key_ids);
411
412
      Certificate_Status_Request(TLS_Data_Reader& reader,
413
                                 uint16_t extension_size,
414
                                 Connection_Side side,
415
                                 Handshake_Type message_type);
416
   private:
417
      std::vector<uint8_t> m_ocsp_names;
418
      std::vector<std::vector<uint8_t>> m_ocsp_keys; // is this field really needed
419
      std::vector<uint8_t> m_extension_bytes;
420
      std::vector<uint8_t> m_response;
421
   };
422
423
/**
424
* Supported Versions from RFC 8446
425
*/
426
class BOTAN_UNSTABLE_API Supported_Versions final : public Extension
427
   {
428
   public:
429
      static Handshake_Extension_Type static_type()
430
34.1k
         { return TLSEXT_SUPPORTED_VERSIONS; }
431
432
12.9k
      Handshake_Extension_Type type() const override { return static_type(); }
433
434
      std::vector<uint8_t> serialize(Connection_Side whoami) const override;
435
436
1.42k
      bool empty() const override { return m_versions.empty(); }
437
438
      Supported_Versions(Protocol_Version version, const Policy& policy);
439
440
      Supported_Versions(Protocol_Version version)
441
0
         {
442
0
         m_versions.push_back(version);
443
0
         }
444
445
      Supported_Versions(TLS_Data_Reader& reader,
446
                         uint16_t extension_size,
447
                         Connection_Side from);
448
449
      bool supports(Protocol_Version version) const;
450
451
20
      const std::vector<Protocol_Version>& versions() const { return m_versions; }
452
   private:
453
      std::vector<Protocol_Version> m_versions;
454
   };
455
456
using Named_Group = Group_Params;
457
458
/**
459
* Unknown extensions are deserialized as this type
460
*/
461
class BOTAN_UNSTABLE_API Unknown_Extension final : public Extension
462
   {
463
   public:
464
      Unknown_Extension(Handshake_Extension_Type type,
465
                        TLS_Data_Reader& reader,
466
                        uint16_t extension_size);
467
468
      std::vector<uint8_t> serialize(Connection_Side whoami) const override; // always fails
469
470
0
      const std::vector<uint8_t>& value() { return m_value; }
471
472
0
      bool empty() const override { return false; }
473
474
3.45M
      Handshake_Extension_Type type() const override { return m_type; }
475
476
0
      bool is_implemented() const override { return false; }
477
478
   private:
479
      Handshake_Extension_Type m_type;
480
      std::vector<uint8_t> m_value;
481
   };
482
483
/**
484
* Represents a block of extensions in a hello message
485
*/
486
class BOTAN_UNSTABLE_API Extensions final
487
   {
488
   public:
489
      std::set<Handshake_Extension_Type> extension_types() const;
490
491
      template<typename T>
492
      T* get() const
493
365k
         {
494
365k
         return dynamic_cast<T*>(get(T::static_type()));
495
365k
         }
Botan::TLS::Certificate_Status_Request* Botan::TLS::Extensions::get<Botan::TLS::Certificate_Status_Request>() const
Line
Count
Source
493
19.8k
         {
494
19.8k
         return dynamic_cast<T*>(get(T::static_type()));
495
19.8k
         }
Botan::TLS::Renegotiation_Extension* Botan::TLS::Extensions::get<Botan::TLS::Renegotiation_Extension>() const
Line
Count
Source
493
95.9k
         {
494
95.9k
         return dynamic_cast<T*>(get(T::static_type()));
495
95.9k
         }
Botan::TLS::Signature_Algorithms* Botan::TLS::Extensions::get<Botan::TLS::Signature_Algorithms>() const
Line
Count
Source
493
92
         {
494
92
         return dynamic_cast<T*>(get(T::static_type()));
495
92
         }
Botan::TLS::Supported_Groups* Botan::TLS::Extensions::get<Botan::TLS::Supported_Groups>() const
Line
Count
Source
493
39.0k
         {
494
39.0k
         return dynamic_cast<T*>(get(T::static_type()));
495
39.0k
         }
Botan::TLS::Supported_Point_Formats* Botan::TLS::Extensions::get<Botan::TLS::Supported_Point_Formats>() const
Line
Count
Source
493
18.2k
         {
494
18.2k
         return dynamic_cast<T*>(get(T::static_type()));
495
18.2k
         }
Botan::TLS::Server_Name_Indicator* Botan::TLS::Extensions::get<Botan::TLS::Server_Name_Indicator>() const
Line
Count
Source
493
54.0k
         {
494
54.0k
         return dynamic_cast<T*>(get(T::static_type()));
495
54.0k
         }
Botan::TLS::Supported_Versions* Botan::TLS::Extensions::get<Botan::TLS::Supported_Versions>() const
Line
Count
Source
493
21.1k
         {
494
21.1k
         return dynamic_cast<T*>(get(T::static_type()));
495
21.1k
         }
Botan::TLS::Session_Ticket* Botan::TLS::Extensions::get<Botan::TLS::Session_Ticket>() const
Line
Count
Source
493
40.1k
         {
494
40.1k
         return dynamic_cast<T*>(get(T::static_type()));
495
40.1k
         }
Botan::TLS::Extended_Master_Secret* Botan::TLS::Extensions::get<Botan::TLS::Extended_Master_Secret>() const
Line
Count
Source
493
33.6k
         {
494
33.6k
         return dynamic_cast<T*>(get(T::static_type()));
495
33.6k
         }
Botan::TLS::Encrypt_then_MAC* Botan::TLS::Extensions::get<Botan::TLS::Encrypt_then_MAC>() const
Line
Count
Source
493
16.4k
         {
494
16.4k
         return dynamic_cast<T*>(get(T::static_type()));
495
16.4k
         }
Botan::TLS::Application_Layer_Protocol_Notification* Botan::TLS::Extensions::get<Botan::TLS::Application_Layer_Protocol_Notification>() const
Line
Count
Source
493
26.7k
         {
494
26.7k
         return dynamic_cast<T*>(get(T::static_type()));
495
26.7k
         }
Botan::TLS::SRTP_Protection_Profiles* Botan::TLS::Extensions::get<Botan::TLS::SRTP_Protection_Profiles>() const
Line
Count
Source
493
308
         {
494
308
         return dynamic_cast<T*>(get(T::static_type()));
495
308
         }
496
497
      template<typename T>
498
      bool has() const
499
174k
         {
500
174k
         return get<T>() != nullptr;
501
174k
         }
bool Botan::TLS::Extensions::has<Botan::TLS::Renegotiation_Extension>() const
Line
Count
Source
499
60.9k
         {
500
60.9k
         return get<T>() != nullptr;
501
60.9k
         }
bool Botan::TLS::Extensions::has<Botan::TLS::Session_Ticket>() const
Line
Count
Source
499
20.2k
         {
500
20.2k
         return get<T>() != nullptr;
501
20.2k
         }
bool Botan::TLS::Extensions::has<Botan::TLS::Application_Layer_Protocol_Notification>() const
Line
Count
Source
499
23.3k
         {
500
23.3k
         return get<T>() != nullptr;
501
23.3k
         }
bool Botan::TLS::Extensions::has<Botan::TLS::Extended_Master_Secret>() const
Line
Count
Source
499
33.6k
         {
500
33.6k
         return get<T>() != nullptr;
501
33.6k
         }
bool Botan::TLS::Extensions::has<Botan::TLS::Certificate_Status_Request>() const
Line
Count
Source
499
19.8k
         {
500
19.8k
         return get<T>() != nullptr;
501
19.8k
         }
bool Botan::TLS::Extensions::has<Botan::TLS::Encrypt_then_MAC>() const
Line
Count
Source
499
16.4k
         {
500
16.4k
         return get<T>() != nullptr;
501
16.4k
         }
Unexecuted instantiation: bool Botan::TLS::Extensions::has<Botan::TLS::Signature_Algorithms>() const
502
503
      bool has(Handshake_Extension_Type type) const
504
385k
         {
505
385k
         return get(type) != nullptr;
506
385k
         }
507
508
      size_t size() const
509
0
         {
510
0
         return m_extensions.size();
511
0
         }
512
513
      void add(std::unique_ptr<Extension> extn);
514
515
      void add(Extension* extn)
516
55.5k
         {
517
55.5k
         add(std::unique_ptr<Extension>(extn));
518
55.5k
         }
519
520
      Extension* get(Handshake_Extension_Type type) const
521
751k
         {
522
751k
         const auto i = std::find_if(m_extensions.cbegin(), m_extensions.cend(),
523
4.45M
                                     [type](const auto &ext) {
524
4.45M
                                        return ext->type() == type;
525
4.45M
                                     });
526
527
751k
         return (i != m_extensions.end()) ? i->get() : nullptr;
528
751k
         }
529
530
      std::vector<uint8_t> serialize(Connection_Side whoami) const;
531
532
      void deserialize(TLS_Data_Reader& reader,
533
                       const Connection_Side from,
534
                       const Handshake_Type message_type);
535
536
      /**
537
       * Take the extension with the given type out of the extensions list.
538
       * Returns a nullptr if the extension didn't exist.
539
       */
540
      template<typename T>
541
      decltype(auto) take()
542
         {
543
         std::unique_ptr<T> out_ptr;
544
545
         auto ext = take(T::static_type());
546
         if (ext != nullptr) {
547
            out_ptr.reset(dynamic_cast<T*>(ext.get()));
548
            BOTAN_ASSERT_NOMSG(out_ptr != nullptr);
549
            ext.release();
550
         }
551
552
         return out_ptr;
553
         }
554
555
      /**
556
       * Take the extension with the given type out of the extensions list.
557
       * Returns a nullptr if the extension didn't exist.
558
       */
559
      std::unique_ptr<Extension> take(Handshake_Extension_Type type);
560
561
      /**
562
      * Remove an extension from this extensions object, if it exists.
563
      * Returns true if the extension existed (and thus is now removed),
564
      * otherwise false (the extension wasn't set in the first place).
565
      *
566
      * Note: not used internally, might be used in Callbacks::tls_modify_extensions()
567
      */
568
      bool remove_extension(Handshake_Extension_Type type)
569
0
         {
570
0
         return take(type) != nullptr;
571
0
         }
572
573
44.9k
      Extensions() = default;
574
      Extensions(Extensions&&) = default;
575
      Extensions& operator=(Extensions&&) = default;
576
577
      Extensions(TLS_Data_Reader& reader, Connection_Side side, Handshake_Type message_type)
578
0
         {
579
0
         deserialize(reader, side, message_type);
580
0
         }
581
582
   private:
583
      Extensions(const Extensions&) = delete;
584
      Extensions& operator=(const Extensions&) = delete;
585
586
      std::vector<std::unique_ptr<Extension>> m_extensions;
587
   };
588
589
}
590
591
}
592
593
#endif