Coverage Report

Created: 2025-08-26 07:54

/src/PcapPlusPlus/Packet++/header/SSLHandshake.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <utility>
4
#include "SSLCommon.h"
5
#include "PointerVector.h"
6
#include "Asn1Codec.h"
7
#include "X509Decoder.h"
8
9
/// @file
10
/// See detailed explanation of the TLS/SSL protocol support in PcapPlusPlus in SSLLayer.h
11
12
/// @namespace pcpp
13
/// @brief The main namespace for the PcapPlusPlus lib
14
namespace pcpp
15
{
16
  /// @class SSLCipherSuite
17
  /// Represents a cipher-suite and enables access all information about it such as all algorithms it encapsulates,
18
  /// its ID (as appears in the client-hello or server-hello messages),
19
  /// its name (e.g "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA") etc. PcapPlusPlus contains static instances of this type
20
  /// for all known cipher-suites and enables access to them through name or ID (see getCipherSuiteByID() and
21
  /// getCipherSuiteByName() ). List of cipher-suite was taken from here:
22
  /// http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
23
  class SSLCipherSuite
24
  {
25
  public:
26
    /// A c'tor for this class, should never be used by a user
27
    /// @param[in] id Cipher-suite ID
28
    /// @param[in] keyExAlg Key-exchange algorithm used in this cipher-suite
29
    /// @param[in] authAlg Authentication algorithm used in this cipher-suite
30
    /// @param[in] symKeyAlg Symmetric key algorithm used in this cipher-suite
31
    /// @param[in] MACAlg MAC algorithm used in this cipher-suite
32
    /// @param[in] name String representation of this cipher-suite
33
    SSLCipherSuite(uint16_t id, SSLKeyExchangeAlgorithm keyExAlg, SSLAuthenticationAlgorithm authAlg,
34
                   SSLSymetricEncryptionAlgorithm symKeyAlg, SSLHashingAlgorithm MACAlg, const char* name)
35
658
        : m_Id(id), m_KeyExAlg(keyExAlg), m_AuthAlg(authAlg), m_SymKeyAlg(symKeyAlg), m_MACAlg(MACAlg), m_Name(name)
36
658
    {}
37
38
    /// @return Cipher-suite ID
39
    uint16_t getID() const
40
0
    {
41
0
      return m_Id;
42
0
    }
43
44
    /// @return String representation of this cipher-suite
45
    std::string asString() const
46
0
    {
47
0
      return m_Name;
48
0
    }
49
50
    /// @return Key-exchange algorithm used in this cipher-suite
51
    SSLKeyExchangeAlgorithm getKeyExchangeAlg() const
52
0
    {
53
0
      return m_KeyExAlg;
54
0
    }
55
56
    /// @return Authentication algorithm used in this cipher-suite
57
    SSLAuthenticationAlgorithm getAuthAlg() const
58
0
    {
59
0
      return m_AuthAlg;
60
0
    }
61
62
    /// @return Symmetric key algorithm used in this cipher-suite
63
    SSLSymetricEncryptionAlgorithm getSymKeyAlg() const
64
0
    {
65
0
      return m_SymKeyAlg;
66
0
    }
67
68
    /// @return MAC algorithm used in this cipher-suite
69
    SSLHashingAlgorithm getMACAlg() const
70
0
    {
71
0
      return m_MACAlg;
72
0
    }
73
74
    /// A static method that returns a cipher-suite instance by ID
75
    /// @param[in] id Cipher-suite ID
76
    /// @return A cipher-suite instance matching this ID or nullptr if ID not found
77
    static SSLCipherSuite* getCipherSuiteByID(uint16_t id);
78
79
    ///  A static method that returns a cipher-suite instance by name
80
    ///  @param[in] name Cipher-suite name (e.g "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA")
81
    ///  @return A cipher-suite instance matching this name or nullptr if name not found
82
    static SSLCipherSuite* getCipherSuiteByName(std::string name);
83
84
  private:
85
    uint16_t m_Id;
86
    SSLKeyExchangeAlgorithm m_KeyExAlg;
87
    SSLAuthenticationAlgorithm m_AuthAlg;
88
    SSLSymetricEncryptionAlgorithm m_SymKeyAlg;
89
    SSLHashingAlgorithm m_MACAlg;
90
    std::string m_Name;
91
  };
92
93
  /// @class SSLExtension
94
  /// Represents a SSL/TLS extension. This is a base class that can represent any type of extension. Inherited classes
95
  /// may contain parsing logic for specific extensions. This class provides capabilities such as getting the
96
  /// extension type, length and viewing the extension data as raw (byte array)
97
  class SSLExtension
98
  {
99
  public:
100
    /// C'tor for this class
101
    /// @param[in] data The raw data for the extension
102
    explicit SSLExtension(uint8_t* data);
103
104
276k
    virtual ~SSLExtension() = default;
105
106
    /// @return The type of the extension as enum
107
    SSLExtensionType getType() const;
108
109
    /// @return The type of the extension as a numeric value
110
    uint16_t getTypeAsInt() const;
111
112
    /// @return The length of the extension data in bytes (not including the type and length fields)
113
    uint16_t getLength() const;
114
115
    /// @return The total length of the extension, including type and length fields and the extension data field
116
    uint16_t getTotalLength() const;
117
118
    /// @return A pointer to the raw data of the extension
119
    uint8_t* getData() const;
120
121
  protected:
122
    /// @struct SSLExtensionStruct
123
    /// Represents the common fields of the extension
124
    struct SSLExtensionStruct
125
    {
126
      /// Extension type
127
      uint16_t extensionType;
128
      /// Extension length
129
      uint16_t extensionDataLength;
130
      /// Extension data as raw (byte array)
131
      uint8_t extensionData[];
132
    };
133
134
    uint8_t* m_RawData;
135
136
    SSLExtensionStruct* getExtensionStruct() const
137
656k
    {
138
656k
      return reinterpret_cast<SSLExtensionStruct*>(m_RawData);
139
656k
    }
140
  };
141
142
  /// @class SSLServerNameIndicationExtension
143
  /// Represents SSL/TLS Server Name Indication extension. Inherits from SSLExtension and add parsing of the hostname
144
  /// written in the extension data
145
  class SSLServerNameIndicationExtension : public SSLExtension
146
  {
147
  public:
148
    /// C'tor for this class
149
    /// @param[in] data The raw data for the extension
150
114k
    explicit SSLServerNameIndicationExtension(uint8_t* data) : SSLExtension(data)
151
114k
    {}
152
153
    /// @return The hostname written in the extension data
154
    std::string getHostName() const;
155
  };
156
157
  /// @class SSLSupportedVersionsExtension
158
  /// Represents TLS Supported Versions extension. Inherits from SSLExtension and adds parsing of the list
159
  /// of supported versions mentioned in the extension data
160
  class SSLSupportedVersionsExtension : public SSLExtension
161
  {
162
  public:
163
    /// C'tor for this class
164
    /// @param[in] data The raw data for the extension
165
4.21k
    explicit SSLSupportedVersionsExtension(uint8_t* data) : SSLExtension(data)
166
4.21k
    {}
167
168
    /// @return The list of supported versions mentioned in the extension data
169
    std::vector<SSLVersion> getSupportedVersions() const;
170
  };
171
172
  /// @class TLSSupportedGroupsExtension
173
  /// Represents TLS Supported Groups extension. Inherits from SSLExtension and adds parsing of the
174
  /// supported groups (Elliptic Curves) mentioned in the extension data
175
  class TLSSupportedGroupsExtension : public SSLExtension
176
  {
177
  public:
178
    /// C'tor for this class
179
    /// @param[in] data The raw data for the extension
180
11.4k
    explicit TLSSupportedGroupsExtension(uint8_t* data) : SSLExtension(data)
181
11.4k
    {}
182
183
    /// @return A vector of the supported groups (also known as "Elliptic Curves")
184
    std::vector<uint16_t> getSupportedGroups() const;
185
  };
186
187
  /// @class TLSECPointFormatExtension
188
  /// Represents TLS EC (Elliptic Curves) Point Format extension. Inherits from SSLExtension and adds parsing of the
189
  /// EC point formats mentioned in the extension data
190
  class TLSECPointFormatExtension : public SSLExtension
191
  {
192
  public:
193
    /// C'tor for this class
194
    /// @param[in] data The raw data for the extension
195
13.0k
    explicit TLSECPointFormatExtension(uint8_t* data) : SSLExtension(data)
196
13.0k
    {}
197
198
    /// @return A vector of the elliptic curves point formats
199
    std::vector<uint8_t> getECPointFormatList() const;
200
  };
201
202
  /// @class SSLx509Certificate
203
  /// Represents a x509v3 certificate. the SSLCertificateMessage class returns an instance of this class as the
204
  /// certificate. Currently this class doesn't do much as it doesn't parse the certificate. It only acts as container
205
  /// to the raw data and returns general info as data as raw, length, etc. In the future I may add full parsing of
206
  /// the certificate
207
  class SSLx509Certificate
208
  {
209
  public:
210
    /// C'tor for this class
211
    /// @param[in] data The raw data of the certificate
212
    /// @param[in] dataLen The length in bytes of the raw data
213
    /// @param[in] allDataExists Certificate messages usually spread on more than 1 packet. So a certificate is
214
    /// likely to split between 2 packets or more. This field indicates whether the raw data contains all
215
    /// certificate data of just a part of it
216
    SSLx509Certificate(uint8_t* data, size_t dataLen, bool allDataExists)
217
22.4k
        : m_Data(data), m_DataLen(dataLen), m_AllDataExists(allDataExists)
218
22.4k
    {}
219
220
    /// @return A pointer to the raw data
221
    uint8_t* getData() const
222
0
    {
223
0
      return m_Data;
224
0
    }
225
226
    /// @return Raw data length
227
    size_t getDataLength() const
228
0
    {
229
0
      return m_DataLen;
230
0
    }
231
232
    /// @return The root ASN.1 record of the certificate data. All the certificate data will be under this
233
    /// record. If the certificate data isn't complete, this method will return nullptr. If the Root ASN.1 record
234
    /// is malformed, an exception is thrown
235
    Asn1SequenceRecord* getRootAsn1Record();
236
237
    /// Parse the certificate data as X509 certificate. If the certificate data isn't complete, this method will
238
    /// return nullptr
239
    /// @return A unique pointer to the parsed X509 certificate
240
    std::unique_ptr<X509Certificate> getX509Certificate();
241
242
    /// Certificate messages usually spread on more than 1 packet. So a certificate is likely to split between 2
243
    /// packets or more. This method provides an indication whether all certificate data exists or only part of it
244
    /// @return True if this data contains all certificate data, false otherwise
245
    bool allDataExists() const
246
0
    {
247
0
      return m_AllDataExists;
248
0
    }
249
250
  private:
251
    std::unique_ptr<Asn1Record> m_Asn1Record;
252
    uint8_t* m_Data;
253
    size_t m_DataLen;
254
    bool m_AllDataExists;
255
  };
256
257
  class SSLHandshakeLayer;
258
259
  /// @class SSLHandshakeMessage
260
  /// A base class for SSL/TLS handshake messages. This is an abstract class and cannot be instantiated. SSL/TLS
261
  /// handshake messages are contained in SSLHandshakeLayer, meaning a SSLHandshakeLayer instance can contain one or
262
  /// more SSLHandshakeMessage instances. For example: one SSLHandshakeLayer may contain a server-hello, certificate,
263
  /// server-key-exchange, and server-hello-done messages (although it's not such a common case, most handshake layers
264
  /// contain 1 handshake message only)
265
  class SSLHandshakeMessage
266
  {
267
  public:
268
139k
    virtual ~SSLHandshakeMessage() = default;
269
270
    /// A factory method for creating instances of handshake messages from raw data
271
    /// @param[in] data The raw data containing 1 handshake message
272
    /// @param[in] dataLen Raw data length in bytes
273
    /// @param[in] container A pointer to the SSLHandshakeLayer instance which will contain the created message.
274
    /// This parameter is required because the handshake message includes a pointer to its container
275
    static SSLHandshakeMessage* createHandshakeMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container);
276
277
    /// @return The handshake message type
278
    virtual SSLHandshakeType getHandshakeType() const;
279
280
    /// @return The handshake message length in bytes. Notice that sometimes the handshake message is divided
281
    /// between several packets, in this case this method will return the length of part of the message in the
282
    /// current packet
283
    virtual size_t getMessageLength() const;
284
285
    /// @return True if current packet contains the entire message or false otherwise. This method is important
286
    /// because sometimes handshake messages are divided in consequent packets (happens a lot in certificate
287
    /// messages which usually contain several KB of data which is larger than standard packet size, so the message
288
    /// is divided between several packets)
289
    virtual bool isMessageComplete() const;
290
291
    /// @return A pointer to the SSLHandshakeLayer instance containing this message
292
    SSLHandshakeLayer* getContainingLayer() const
293
0
    {
294
0
      return m_Container;
295
0
    }
296
297
    /// @return A string representation of the message type (e.g "Client Hello message")
298
    virtual std::string toString() const = 0;
299
300
  protected:
301
    SSLHandshakeMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container);
302
303
    uint8_t* m_Data;
304
    size_t m_DataLen;
305
    SSLHandshakeLayer* m_Container;
306
  };
307
308
  /// @class SSLClientHelloMessage
309
  /// Represents a client-hello message (type 1). Inherits from SSLHandshakeMessage and adds parsing of all fields
310
  /// of this message including the message extensions, cipher-suite list, etc.
311
  class SSLClientHelloMessage : public SSLHandshakeMessage
312
  {
313
  public:
314
    /// @struct ClientHelloTLSFingerprint
315
    /// A struct that contains all the elements needed for creating a Client Hello TLS fingerprinting:
316
    /// TLS version, a list of Cipher Suite IDs, a list of Extensions IDs, a list of support groups and a list of
317
    /// EC point formats.
318
    /// You can read more about this in SSLClientHelloMessage#generateTLSFingerprint().
319
    /// This struct contains methods to extract the TLS fingerprint itself: toString() and toMD5()
320
    struct ClientHelloTLSFingerprint
321
    {
322
      /// TLS version
323
      uint16_t tlsVersion;
324
      /// A list of Cipher Suite IDs
325
      std::vector<uint16_t> cipherSuites;
326
      /// A list of extension IDs
327
      std::vector<uint16_t> extensions;
328
      /// A list of Suppotred Groups taken from the "supported groups" TLS extension (if exist in the message)
329
      std::vector<uint16_t> supportedGroups;
330
      /// A list of EC point formats taken from the "EC point formats" TLS extension (if exist in the message)
331
      std::vector<uint8_t> ecPointFormats;
332
333
      /// @return A string representing the TLS fingerprint, for example:
334
      /// <b>771,4866-4867-4865-255,0-11-10-35-22-23-13-43-45-51,29-23-30-25-24,0-1-2</b>
335
      ///
336
      /// This string has the following format:
337
      /// <b>TLSVersion,CipherSuiteIDs,ExtensionIDs,SupportedGroups,ECPointFormats</b>
338
      ///
339
      /// The extension IDs, supported groups and EC point formats are each separated by a "-".
340
      /// If the message doesn't include the "supported groups" or "EC point formats" extensions, they will be
341
      /// replaced by an empty string for example: <b>771,4866-4867-4865-255,0-11-10-35-22-23-13-43-45-51,,</b>
342
      std::string toString();
343
344
      /// @return An MD5 hash of the string generated by toString()
345
      std::string toMD5();
346
347
      /// @return A pair of the string and MD5 hash (string is first, MD5 is second).
348
      /// If you want both this method is more efficient than calling toString() and toMD5() separately
349
      std::pair<std::string, std::string> toStringAndMD5();
350
    };
351
352
    /// C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and shouldn't
353
    /// be used by a user
354
    /// @param[in] data The message as raw data
355
    /// @param[in] dataLen Message raw data length in bytes
356
    /// @param[in] container The SSL handshake layer which shall contain this message
357
    SSLClientHelloMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container);
358
359
24.0k
    ~SSLClientHelloMessage() override = default;
360
361
    /// @return A struct containing common fields for client-hello and server-hello messages. Notice this points
362
    /// directly to the data, so every change will change the actual packet data
363
    ssl_tls_client_server_hello* getClientHelloHeader() const
364
8.91k
    {
365
8.91k
      return reinterpret_cast<ssl_tls_client_server_hello*>(m_Data);
366
8.91k
    }
367
368
    /// @return Handshake SSL/TLS version (notice it may be different than SSLLayer#getRecordVersion(). Each
369
    /// client-hello or server-hello message has both record version and handshake version and they may differ from
370
    /// one another)
371
    SSLVersion getHandshakeVersion() const;
372
373
    /// @return Session ID length in bytes. If server-hello message doesn't include session ID 0 will be returned
374
    uint8_t getSessionIDLength() const;
375
376
    /// @return Session ID as byte array. If server-hello message doesn't include session ID nullptr will be
377
    /// returned
378
    uint8_t* getSessionID() const;
379
380
    /// @return The number of cipher-suites included in this message
381
    int getCipherSuiteCount() const;
382
383
    /// Get a pointer to a cipher-suite by index. The cipher-suites are numbered according to their order of
384
    /// appearance in the message. If index is out of bounds (less than 0 or larger than total amount of cipher
385
    /// suites) nullptr will be returned. nullptr will also be returned if the cipher-suite ID is unknown. If you
386
    /// still want to get the cipher-suite ID you can use getCipherSuiteID()
387
    /// @param[in] index The index of the cipher-suite to return
388
    /// @return The pointer to the cipher-suite object or nullptr if index is out of bounds
389
    SSLCipherSuite* getCipherSuite(int index) const;
390
391
    /// Get the cipher-suite ID by index. This method just parses the ID from the client-hello message and returns
392
    /// it. To get more information on the cipher-suite you can use the getCipherSuite() method
393
    /// @param[in] index The index of the cipher-suite to return
394
    /// @param[out] isValid Set to "true" if parsing succeeded and the return value is valid or "false" if:
395
    /// (1) the index is out-of-bounds (less than 0 or larger than total amount of cipher suites) or (2) the parsing
396
    /// failed. If the value is "false" the return value can be ignored
397
    /// @return The cipher-suite ID if "isValid" is set to "true". If "isValid" is set to "false" the return value
398
    /// can be ignored
399
    uint16_t getCipherSuiteID(int index, bool& isValid) const;
400
401
    /// @return The value of the compression method byte
402
    uint8_t getCompressionMethodsValue() const;
403
404
    /// @return The number of extensions in this message
405
    int getExtensionCount() const;
406
407
    /// @return The size (in bytes) of all extensions data in this message. Extracted from the "extensions length"
408
    /// field
409
    uint16_t getExtensionsLength() const;
410
411
    /// Get a pointer to an extension by index. The extensions are numbered according to their order of appearance
412
    /// in the message. If index is out of bounds (less than 0 or larger than total amount of extensions) nullptr
413
    /// will be returned
414
    /// @param[in] index The index of the extension to return
415
    /// @return The pointer to the extension or nullptr if index is out of bounds
416
    SSLExtension* getExtension(int index) const;
417
418
    /// Get a pointer to an extension by numeric type field. Every extension has a 2-byte numeric value representing
419
    /// its type (for example: renegotiation info extension type is 0x1ff). This method gets the type and returns a
420
    /// pointer to the extension object
421
    /// @param[in] type The 2-byte numeric type of the extension
422
    /// @return A pointer to the extension object of nullptr if this type doesn't exist in this message
423
    SSLExtension* getExtensionOfType(uint16_t type) const;
424
425
    /// Get a pointer to an extension by its enum type
426
    /// @param[in] type The type of extension to return
427
    /// @return A pointer to the extension object or nullptr if this type doesn't exist in this message
428
    SSLExtension* getExtensionOfType(SSLExtensionType type) const;
429
430
    /// Get a pointer to an extension by its class type. This is a templated method that is used with the type of
431
    /// the requested extension and returns the first extension instance of this type
432
    /// @return A pointer to the extension object or nullptr if this extension type doesn't exist in this message
433
    template <class TExtension> TExtension* getExtensionOfType() const;
434
435
    /// TLS fingerprinting is a way to identify client applications using the details in the TLS Client Hello
436
    /// packet. It was initially introduced by Lee Brotherston in his 2015 research:
437
    /// <https://blog.squarelemon.com/tls-fingerprinting/> This implementation of TLS fingerprint is a C++ version
438
    /// of Salesforce's JA3 open source project (originally written in Python and Zeek):
439
    /// <https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967>
440
    /// @return A SSLClientHelloMessage#ClientHelloTLSFingerprint struct that contains all the elements needed for
441
    /// creating a TLS fingerprint out of this Client Hello message. This struct has also methods to extract the TLS
442
    /// fingerprint itself in a string or MD5 formats
443
    ClientHelloTLSFingerprint generateTLSFingerprint() const;
444
445
    // implement abstract methods
446
447
    std::string toString() const override;
448
449
  private:
450
    PointerVector<SSLExtension> m_ExtensionList;
451
  };
452
453
  /// @class SSLServerHelloMessage
454
  /// Represents SSL/TLS server-hello message (type 2). Inherits from SSLHandshakeMessage and adds parsing of all
455
  /// fields of this message including the message extensions, cipher-suite, etc.
456
  class SSLServerHelloMessage : public SSLHandshakeMessage
457
  {
458
  public:
459
    /// @struct ServerHelloTLSFingerprint
460
    /// A struct that contains all the elements needed for creating a Server Hello TLS fingerprinting:
461
    /// TLS version, Cipher Suite ID, and a list of Extensions IDs.
462
    /// You can read more about this in SSLServerHelloMessage#generateTLSFingerprint().
463
    /// This struct contains methods to extract the TLS fingerprint itself: toString() and toMD5()
464
    struct ServerHelloTLSFingerprint
465
    {
466
      /// TLS version
467
      uint16_t tlsVersion;
468
      /// Cipher Suite ID
469
      uint16_t cipherSuite;
470
      /// A list of extension IDs
471
      std::vector<uint16_t> extensions;
472
473
      /// @return A string representing the TLS fingerprint, for example: <b>771,49195,65281-16-11</b>
474
      ///
475
      /// This string has the following format: <b>TLSVersion,Cipher,Extensions</b>
476
      ///
477
      /// The extension ID are separated with a "-"
478
      std::string toString();
479
480
      /// @return An MD5 hash of the string generated by toString()
481
      std::string toMD5();
482
483
      /// @return A pair of the string and MD5 hash (string is first, MD5 is second).
484
      /// If you want both this method is more efficient than calling toString() and toMD5() separately
485
      std::pair<std::string, std::string> toStringAndMD5();
486
    };
487
488
    /// C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and shouldn't
489
    /// be used by a user
490
    /// @param[in] data The message as raw data
491
    /// @param[in] dataLen Message raw data length in bytes
492
    /// @param[in] container The SSL handshake layer which shall contain this message
493
    SSLServerHelloMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container);
494
495
22.4k
    ~SSLServerHelloMessage() override = default;
496
497
    /// @return A struct containing common fields for client-hello and server-hello messages. Notice this points
498
    /// directly to the data, so every change will change the actual packet data
499
    ssl_tls_client_server_hello* getServerHelloHeader() const
500
6.51k
    {
501
6.51k
      return reinterpret_cast<ssl_tls_client_server_hello*>(m_Data);
502
6.51k
    }
503
504
    /// @return Handshake SSL/TLS version (notice it may be different than SSLLayer#getRecordVersion(). Each
505
    /// client-hello or server-hello message has both record version and handshake version and they may differ from
506
    /// one another).
507
    ///
508
    /// <b>NOTE:</b> for TLS 1.3 the handshake version written in ssl_tls_client_server_hello::handshakeVersion is
509
    /// still TLS 1.2, so a special check is made here see if a SupportedVersions extension exists and if so extract
510
    /// the version from it. This is the most straight-forward way to detect TLS 1.3.
511
    SSLVersion getHandshakeVersion() const;
512
513
    /// @return Session ID length in bytes. If server-hello message doesn't include session ID 0 will be returned
514
    uint8_t getSessionIDLength() const;
515
516
    /// @return Session ID as byte array. If server-hello message doesn't include session ID nullptr will be
517
    /// returned
518
    uint8_t* getSessionID() const;
519
520
    /// @return A pointer to the cipher suite encapsulated in this message (server-hello message contains one
521
    /// cipher-suite, the one that will be used to for encryption between client and server). May return nullptr
522
    /// if the parsing of the message failed or the cipher-suite ID is unknown. If you still want to get the
523
    /// cipher-suite ID you can use the getCipherSuiteID() method
524
    SSLCipherSuite* getCipherSuite() const;
525
526
    /// Get the cipher-suite ID. This method just parses the ID from the server-hello message and returns it.
527
    /// To get more information on the cipher-suite you can use the getCipherSuite() method
528
    /// @param[out] isValid Set to "true" if parsing succeeded and the return value is valid or "false" otherwise.
529
    /// If the value is "false" the return value can be ignored
530
    /// @return The cipher-suite ID if "isValid" is set to "true". If "isValid" is set to "false" the return value
531
    /// can be ignored
532
    uint16_t getCipherSuiteID(bool& isValid) const;
533
534
    /// @return The value of the compression method byte
535
    uint8_t getCompressionMethodsValue() const;
536
537
    /// @return The number of extensions in this message
538
    int getExtensionCount() const;
539
540
    /// @return The size (in bytes) of all extensions data in this message. Extracted from the "extensions length"
541
    /// field
542
    uint16_t getExtensionsLength() const;
543
544
    /// Get a pointer to an extension by index. The extensions are numbered according to their order of appearance
545
    /// in the message. If index is out of bounds (less than 0 or larger than total amount of extensions) nullptr
546
    /// will be returned
547
    /// @param[in] index The index of the extension to return
548
    /// @return The pointer to the extension or nullptr if index is out of bounds
549
    SSLExtension* getExtension(int index) const;
550
551
    /// Get a pointer to an extension by numeric type field. Every extension has a 2-byte numeric value representing
552
    /// its type (for example: renegotiation info extension type is 0x1ff). This method gets the type and returns a
553
    /// pointer to the extension object
554
    /// @param[in] type The 2-byte numeric type of the extension
555
    /// @return A pointer to the extension object of nullptr if this type doesn't exist in this message
556
    SSLExtension* getExtensionOfType(uint16_t type) const;
557
558
    /// Get a pointer to an extension by its enum type
559
    /// @param[in] type The type of extension to return
560
    /// @return A pointer to the extension object or nullptr if this type doesn't exist in this message
561
    SSLExtension* getExtensionOfType(SSLExtensionType type) const;
562
563
    /// Get a pointer to an extension by its class type. This is a templated method that is used with the type of
564
    /// the requested extension and returns the first extension instance of this type
565
    /// @return A pointer to the extension object or nullptr if this extension type doesn't exist in this message
566
    template <class TExtension> TExtension* getExtensionOfType() const;
567
568
    /// ServerHello TLS fingerprinting is a way to fingerprint TLS Server Hello messages. In conjunction with
569
    /// ClientHello TLS fingerprinting it can assist in identifying specific client-server communication (for
570
    /// example: a malware connecting to its backend server).
571
    /// ServerHello TLS fingerprinting was introduced in Salesforce's JA3S open source project:
572
    /// <https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967>
573
    /// This implementation is a C++ version of Salesforce's JAS3 (originally written in Python and Zeek)
574
    /// @return A SSLServerHelloMessage#ServerHelloTLSFingerprint struct that contains all the elements needed for
575
    /// creating a TLS fingerprint out of this Server Hello message. This struct has also methods to extract the TLS
576
    /// fingerprint itself in a string or MD5 formats
577
    ServerHelloTLSFingerprint generateTLSFingerprint() const;
578
579
    // implement abstract methods
580
581
    std::string toString() const override;
582
583
  private:
584
    PointerVector<SSLExtension> m_ExtensionList;
585
  };
586
587
  /// @class SSLCertificateMessage
588
  /// Represents SSL/TLS certificate message (type 11). Inherits from SSLHandshakeMessage and adds parsing
589
  /// functionality such as extracting the certificates data. Notice that in most cases this message is spread over
590
  /// more than 1 packet as its size is too big for a single packet. So SSLCertificateMessage instance will be created
591
  /// just for the first part of the message - the one encapsulated in the first packet. Other parts (encapsulated in
592
  /// the following packets) won't be recognized as SSLCertificateMessage messages
593
  class SSLCertificateMessage : public SSLHandshakeMessage
594
  {
595
  public:
596
    /// C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be
597
    /// used by a user
598
    /// @param[in] data The message as raw data
599
    /// @param[in] dataLen Message raw data length in bytes
600
    /// @param[in] container The SSL handshake layer which shall contain this message
601
    SSLCertificateMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container);
602
603
8.30k
    ~SSLCertificateMessage() override = default;
604
605
    /// @return The number of certificates encapsulated in this message (as written in the 'length' field of the
606
    /// message). Notice that because the message may spread over several packets, not all certificates will
607
    /// necessarily be in this packet. So, for example, there may be a case where this method return 3 (message
608
    /// contains 3 certificates) but this message actually contains only 1 certificate as the other 2 are spread
609
    /// over the other packets
610
    int getNumOfCertificates() const;
611
612
    /// Get a certificate by index
613
    /// @param[in] index The index of the certificate to retrieve
614
    /// @return A pointer to the certificate object. Notice that if index < 0 or index > num of certificates
615
    /// encapsulated in current packet a nullptr value will be returned
616
    SSLx509Certificate* getCertificate(int index) const;
617
618
    // implement abstract methods
619
620
    std::string toString() const override;
621
622
  private:
623
    PointerVector<SSLx509Certificate> m_CertificateList;
624
  };
625
626
  /// @class SSLHelloRequestMessage
627
  /// Represents SSL/TLS hello-request message (type 0). This message has no additional payload except for the common
628
  /// payload described in SSLHandshakeMessage
629
  class SSLHelloRequestMessage : public SSLHandshakeMessage
630
  {
631
  public:
632
    /// C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be
633
    /// used by a user
634
    /// @param[in] data The message as raw data
635
    /// @param[in] dataLen Message raw data length in bytes
636
    /// @param[in] container The SSL handshake layer which shall contain this message
637
    SSLHelloRequestMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container)
638
25.1k
        : SSLHandshakeMessage(data, dataLen, container)
639
25.1k
    {}
640
641
    ~SSLHelloRequestMessage() override = default;
642
643
    // implement abstract methods
644
645
    std::string toString() const override;
646
  };
647
648
  /// @class SSLServerKeyExchangeMessage
649
  /// Represents SSL/TLS server-key-exchange message (type 12). Inherits from SSLHandshakeMessage and adds parsing
650
  /// functionality such as getting the server key exchange params as raw data (parsing of this may be added in the
651
  /// future)
652
  class SSLServerKeyExchangeMessage : public SSLHandshakeMessage
653
  {
654
  public:
655
    /// C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be
656
    /// used by a user
657
    /// @param[in] data The message as raw data
658
    /// @param[in] dataLen Message raw data length in bytes
659
    /// @param[in] container The SSL handshake layer which shall contain this message
660
    SSLServerKeyExchangeMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container)
661
4.34k
        : SSLHandshakeMessage(data, dataLen, container)
662
4.34k
    {}
663
664
    ~SSLServerKeyExchangeMessage() override = default;
665
666
    /// @return A pointer to the raw data of the server key exchange params. Currently this data can only returned
667
    /// as raw, parsing may be added in the future. Notice that if the message is spread over more than 1 packet in
668
    /// a way params doesn't exist in the first packet, nullptr will be returned
669
    uint8_t* getServerKeyExchangeParams() const;
670
671
    /// @return The size of the params field. Notice that if the message is spread over more than 1 packet in a way
672
    /// the ssl_tls_handshake_layer cannot be parsed from the packet, 0 will be returned. Also, if only part of the
673
    /// params exist in current packet (and the rest are on consequent packets), the size that will be returned is
674
    /// the size of the part that exists in the current packet (and not total size of params)
675
    size_t getServerKeyExchangeParamsLength() const;
676
677
    // implement abstract methods
678
679
    std::string toString() const override;
680
  };
681
682
  /// @class SSLClientKeyExchangeMessage
683
  /// Represents SSL/TLS client-key-exchange message (type 16). Inherits from SSLHandshakeMessage and adds parsing
684
  /// functionality such as getting the server key exchange params as raw data (parsing of this may be added in the
685
  /// future)
686
  class SSLClientKeyExchangeMessage : public SSLHandshakeMessage
687
  {
688
  public:
689
    /// C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be
690
    /// used by a user
691
    /// @param[in] data The message as raw data
692
    /// @param[in] dataLen Message raw data length in bytes
693
    /// @param[in] container The SSL handshake layer which shall contain this message
694
    SSLClientKeyExchangeMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container)
695
2.11k
        : SSLHandshakeMessage(data, dataLen, container)
696
2.11k
    {}
697
698
    ~SSLClientKeyExchangeMessage() override = default;
699
700
    /// @return A pointer to the raw data of the server key exchange params. Currently this data can only be
701
    /// returned as raw, parsing may be added in the future. Notice that if the message is spread over more than 1
702
    /// packet in a way params doesn't exist in the first packet, nullptr will be returned
703
    uint8_t* getClientKeyExchangeParams() const;
704
705
    /// @return The size of the params field. Notice that if the message is spread over more than 1 packet in a way
706
    /// the ssl_tls_handshake_layer cannot be parsed from the packet, 0 will be returned. Also, if only part of the
707
    /// params exist in current packet (and the rest are on consequent packets), the size that will be returned is
708
    /// the size of the part that exists in the current packet (and not the total size of params)
709
    size_t getClientKeyExchangeParamsLength() const;
710
711
    // implement abstract methods
712
713
    std::string toString() const override;
714
  };
715
716
  /// @class SSLCertificateRequestMessage
717
  /// Represents SSL/TLS certificate-request message (type 13). Inherits from SSLHandshakeMessage and adds parsing
718
  /// functionality such as retrieving client certificate types and authority data
719
  class SSLCertificateRequestMessage : public SSLHandshakeMessage
720
  {
721
  public:
722
    /// C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be
723
    /// used by a user
724
    /// @param[in] data The message as raw data
725
    /// @param[in] dataLen Message raw data length in bytes
726
    /// @param[in] container The SSL handshake layer which shall contain this message
727
    SSLCertificateRequestMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container);
728
729
13.4k
    ~SSLCertificateRequestMessage() override = default;
730
731
    /// @return A reference to a vector containing all client certificate types exist in this message
732
    std::vector<SSLClientCertificateType>& getCertificateTypes();
733
734
    /// @return A pointer to the certificate authority data as raw data (byte array). Parsing of this data may be
735
    /// added in the future. Notice that if this message is spread over several packets in a way none of the
736
    /// certificate authority data exists in this packet, nullptr will be returned
737
    uint8_t* getCertificateAuthorityData() const;
738
739
    /// @return The length of certificate authority data returned by getCertificateAuthorityData(). Notice that if
740
    /// this message is spread over several packets in a way none of certificate authority data exists in the
741
    /// current packet, 0 will be returned. Also, if some of the data exists in the consequent packets, the length
742
    /// that will be returned is the length of data exists in the current packet only (and not the total length)
743
    size_t getCertificateAuthorityLength() const;
744
745
    // implement abstract methods
746
747
    std::string toString() const override;
748
749
  private:
750
    std::vector<SSLClientCertificateType> m_ClientCertificateTypes;
751
  };
752
753
  /// @class SSLServerHelloDoneMessage
754
  /// Represents SSL/TLS server-hello-done message (type 14). This message has no additional payload except for the
755
  /// common payload described in SSLHandshakeMessage
756
  class SSLServerHelloDoneMessage : public SSLHandshakeMessage
757
  {
758
  public:
759
    /// C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be
760
    /// used by a user
761
    /// @param[in] data The message as raw data
762
    /// @param[in] dataLen Message raw data length in bytes
763
    /// @param[in] container The SSL handshake layer which shall contain this message
764
    SSLServerHelloDoneMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container)
765
1.31k
        : SSLHandshakeMessage(data, dataLen, container)
766
1.31k
    {}
767
768
    ~SSLServerHelloDoneMessage() override = default;
769
770
    // implement abstract methods
771
772
    std::string toString() const override;
773
  };
774
775
  /// @class SSLCertificateVerifyMessage
776
  /// Represents SSL/TLS certificate-verify message (type 15). Inherits from SSLHandshakeMessage and adds parsing
777
  /// functionality such as retrieving signed hash data as raw data (parsing may be added in the future)
778
  /// @todo This message type wasn't tested in unit-tests
779
  class SSLCertificateVerifyMessage : public SSLHandshakeMessage
780
  {
781
  public:
782
    /// C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be
783
    /// used by a user
784
    /// @param[in] data The message as raw data
785
    /// @param[in] dataLen Message raw data length in bytes
786
    /// @param[in] container The SSL handshake layer which shall contain this message
787
    SSLCertificateVerifyMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container)
788
150
        : SSLHandshakeMessage(data, dataLen, container)
789
150
    {}
790
791
    ~SSLCertificateVerifyMessage() override = default;
792
793
    /// @return A pointer to the signed hash data as raw data (byte array). Parsing of this data may be added
794
    /// in the future. Notice that if this message is spread over several packets in a way none of the signed hash
795
    /// data exists in this packet, nullptr will be returned
796
    uint8_t* getSignedHash() const;
797
798
    /// @return The length of signed hash data returned by getSignedHash(). Notice that if this message is spread
799
    /// over several packets in a way none of this data exists in the current packet, 0 will be returned. Also, if
800
    /// some of the data exists in the consequent packets, the length that will be returned will be the length of
801
    /// data exists in the current packet only (and not the total length)
802
    size_t getSignedHashLength() const;
803
804
    // implement abstract methods
805
806
    std::string toString() const override;
807
  };
808
809
  /// @class SSLFinishedMessage
810
  /// Represents SSL/TLS finished message (type 20). Inherits from SSLHandshakeMessage and adds parsing
811
  /// functionality such as retrieving signed hash data as raw data (parsing may be added in the future)
812
  /// @todo This message type wasn't tested in unit-tests
813
  class SSLFinishedMessage : public SSLHandshakeMessage
814
  {
815
  public:
816
    /// C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be
817
    /// used by a user
818
    /// @param[in] data The message as raw data
819
    /// @param[in] dataLen Message raw data length in bytes
820
    /// @param[in] container The SSL handshake layer which shall contain this message
821
    SSLFinishedMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container)
822
1.22k
        : SSLHandshakeMessage(data, dataLen, container)
823
1.22k
    {}
824
825
    ~SSLFinishedMessage() override = default;
826
827
    /// @return A pointer to the signed hash data as raw data (byte array). Parsing of this data may be added
828
    /// in the future. Notice that if this message is spread over several packets in a way none of the signed hash
829
    /// data exists in this packet, nullptr will be returned
830
    uint8_t* getSignedHash() const;
831
832
    /// @return The length of signed hash data returned by getSignedHash(). Notice that if the message is spread
833
    /// over several packets in a way none of this data exists in the current packet, 0 will be returned. Also, if
834
    /// some of the data exists in the consequent packets, the length that will be returned will be the length of
835
    /// data exists in the current packet only (and not the total length)
836
    size_t getSignedHashLength() const;
837
838
    // implement abstract methods
839
840
    std::string toString() const override;
841
  };
842
843
  /// @class SSLNewSessionTicketMessage
844
  /// Represents SSL/TLS new-session-ticket message (type 4). Inherits from SSLHandshakeMessage and adds parsing
845
  /// functionality such as retrieving session ticket data as raw data (parsing may be added in the future)
846
  class SSLNewSessionTicketMessage : public SSLHandshakeMessage
847
  {
848
  public:
849
    /// C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be
850
    /// used by a user
851
    /// @param[in] data The message as raw data
852
    /// @param[in] dataLen Message raw data length in bytes
853
    /// @param[in] container The SSL handshake layer which shall contain this message
854
    SSLNewSessionTicketMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container)
855
1.78k
        : SSLHandshakeMessage(data, dataLen, container)
856
1.78k
    {}
857
858
    ~SSLNewSessionTicketMessage() override = default;
859
860
    /// @return A pointer to the session ticket data as raw data (byte array). Parsing of this data may be added
861
    /// in the future. Notice that if this message is spread over several packets in a way none of the signed hash
862
    /// data exists in current packet, nullptr will be returned
863
    uint8_t* getSessionTicketData() const;
864
865
    /// @return The length of session ticket data returned by getSessionTicketData(). Notice that if this message is
866
    /// spread over several packets in a way none of this data exists in the current packet, 0 will be returned.
867
    /// Also, if some of the data exist in the consequent packets, the length that will be returned will be the
868
    /// length of the data existing in the current packet only (and not the total length)
869
    size_t getSessionTicketDataLength() const;
870
871
    // implement abstract methods
872
873
    std::string toString() const override;
874
  };
875
876
  /// @class SSLUnknownMessage
877
  /// Represents an unknown type of message or an encrypted message that PcapPlusPlus can't determine its type. In
878
  /// these cases length can't always be determined from the message itself (especially if the message is encrypted),
879
  /// so the length of this message will always be the size counted from message start until the end of the layer
880
  class SSLUnknownMessage : public SSLHandshakeMessage
881
  {
882
  public:
883
    /// C'tor for this class. Currently only in use in SSLHandshakeMessage::createHandshakeMessage() and should be
884
    /// used by a user
885
    /// @param[in] data The message as raw data
886
    /// @param[in] dataLen Message raw data length in bytes
887
    /// @param[in] container The SSL handshake layer which shall contain this message
888
    SSLUnknownMessage(uint8_t* data, size_t dataLen, SSLHandshakeLayer* container)
889
34.9k
        : SSLHandshakeMessage(data, dataLen, container)
890
34.9k
    {}
891
892
    ~SSLUnknownMessage() override = default;
893
894
    // implement virtual and abstract methods
895
896
    /// @return Always ::SSL_HANDSHAKE_UNKNOWN (overridden from SSLHandshakeMessage)
897
    SSLHandshakeType getHandshakeType() const override;
898
899
    /// @return The length of the data from message start until the end of the layer. Since it's an unknown type
900
    /// or an encrypted message the length parsed from the message can't be guaranteed to be the correct length.
901
    /// That's why the length returned is the size until the end of the layer
902
    size_t getMessageLength() const override;
903
904
    std::string toString() const override;
905
  };
906
907
  template <class TExtension> TExtension* SSLClientHelloMessage::getExtensionOfType() const
908
17.8k
  {
909
17.8k
    size_t vecSize = m_ExtensionList.size();
910
121k
    for (size_t i = 0; i < vecSize; i++)
911
111k
    {
912
111k
      SSLExtension* curElem = const_cast<SSLExtension*>(m_ExtensionList.at(i));
913
111k
      if (dynamic_cast<TExtension*>(curElem) != nullptr)
914
7.39k
        return static_cast<TExtension*>(curElem);
915
111k
    }
916
917
10.4k
    return nullptr;
918
17.8k
  }
pcpp::SSLServerNameIndicationExtension* pcpp::SSLClientHelloMessage::getExtensionOfType<pcpp::SSLServerNameIndicationExtension>() const
Line
Count
Source
908
4.45k
  {
909
4.45k
    size_t vecSize = m_ExtensionList.size();
910
9.24k
    for (size_t i = 0; i < vecSize; i++)
911
7.44k
    {
912
7.44k
      SSLExtension* curElem = const_cast<SSLExtension*>(m_ExtensionList.at(i));
913
7.44k
      if (dynamic_cast<TExtension*>(curElem) != nullptr)
914
2.65k
        return static_cast<TExtension*>(curElem);
915
7.44k
    }
916
917
1.80k
    return nullptr;
918
4.45k
  }
pcpp::SSLSupportedVersionsExtension* pcpp::SSLClientHelloMessage::getExtensionOfType<pcpp::SSLSupportedVersionsExtension>() const
Line
Count
Source
908
4.45k
  {
909
4.45k
    size_t vecSize = m_ExtensionList.size();
910
50.6k
    for (size_t i = 0; i < vecSize; i++)
911
46.4k
    {
912
46.4k
      SSLExtension* curElem = const_cast<SSLExtension*>(m_ExtensionList.at(i));
913
46.4k
      if (dynamic_cast<TExtension*>(curElem) != nullptr)
914
288
        return static_cast<TExtension*>(curElem);
915
46.4k
    }
916
917
4.16k
    return nullptr;
918
4.45k
  }
pcpp::TLSSupportedGroupsExtension* pcpp::SSLClientHelloMessage::getExtensionOfType<pcpp::TLSSupportedGroupsExtension>() const
Line
Count
Source
908
4.45k
  {
909
4.45k
    size_t vecSize = m_ExtensionList.size();
910
31.3k
    for (size_t i = 0; i < vecSize; i++)
911
29.0k
    {
912
29.0k
      SSLExtension* curElem = const_cast<SSLExtension*>(m_ExtensionList.at(i));
913
29.0k
      if (dynamic_cast<TExtension*>(curElem) != nullptr)
914
2.17k
        return static_cast<TExtension*>(curElem);
915
29.0k
    }
916
917
2.28k
    return nullptr;
918
4.45k
  }
pcpp::TLSECPointFormatExtension* pcpp::SSLClientHelloMessage::getExtensionOfType<pcpp::TLSECPointFormatExtension>() const
Line
Count
Source
908
4.45k
  {
909
4.45k
    size_t vecSize = m_ExtensionList.size();
910
30.4k
    for (size_t i = 0; i < vecSize; i++)
911
28.2k
    {
912
28.2k
      SSLExtension* curElem = const_cast<SSLExtension*>(m_ExtensionList.at(i));
913
28.2k
      if (dynamic_cast<TExtension*>(curElem) != nullptr)
914
2.27k
        return static_cast<TExtension*>(curElem);
915
28.2k
    }
916
917
2.17k
    return nullptr;
918
4.45k
  }
919
920
  template <class TExtension> TExtension* SSLServerHelloMessage::getExtensionOfType() const
921
10.1k
  {
922
10.1k
    size_t vecSize = m_ExtensionList.size();
923
20.9k
    for (size_t i = 0; i < vecSize; i++)
924
12.1k
    {
925
12.1k
      SSLExtension* curElem = const_cast<SSLExtension*>(m_ExtensionList.at(i));
926
12.1k
      if (dynamic_cast<TExtension*>(curElem) != nullptr)
927
1.41k
        return static_cast<TExtension*>(curElem);
928
12.1k
    }
929
930
8.72k
    return nullptr;
931
10.1k
  }
pcpp::SSLServerNameIndicationExtension* pcpp::SSLServerHelloMessage::getExtensionOfType<pcpp::SSLServerNameIndicationExtension>() const
Line
Count
Source
921
3.37k
  {
922
3.37k
    size_t vecSize = m_ExtensionList.size();
923
6.23k
    for (size_t i = 0; i < vecSize; i++)
924
3.49k
    {
925
3.49k
      SSLExtension* curElem = const_cast<SSLExtension*>(m_ExtensionList.at(i));
926
3.49k
      if (dynamic_cast<TExtension*>(curElem) != nullptr)
927
636
        return static_cast<TExtension*>(curElem);
928
3.49k
    }
929
930
2.74k
    return nullptr;
931
3.37k
  }
pcpp::SSLSupportedVersionsExtension* pcpp::SSLServerHelloMessage::getExtensionOfType<pcpp::SSLSupportedVersionsExtension>() const
Line
Count
Source
921
6.75k
  {
922
6.75k
    size_t vecSize = m_ExtensionList.size();
923
14.6k
    for (size_t i = 0; i < vecSize; i++)
924
8.68k
    {
925
8.68k
      SSLExtension* curElem = const_cast<SSLExtension*>(m_ExtensionList.at(i));
926
8.68k
      if (dynamic_cast<TExtension*>(curElem) != nullptr)
927
778
        return static_cast<TExtension*>(curElem);
928
8.68k
    }
929
930
5.97k
    return nullptr;
931
6.75k
  }
932
}  // namespace pcpp