Coverage Report

Created: 2025-09-27 08:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/header/Asn1Codec.h
Line
Count
Source
1
#pragma once
2
3
#include <string>
4
#include <memory>
5
#include <typeinfo>
6
#include <stdexcept>
7
#include <sstream>
8
#include <chrono>
9
#include <bitset>
10
#include "PointerVector.h"
11
12
/// @file
13
14
/// @namespace pcpp
15
/// @brief The main namespace for the PcapPlusPlus lib
16
namespace pcpp
17
{
18
  /// An enum for representing ASN.1 tag class
19
  enum class Asn1TagClass : uint8_t
20
  {
21
    /// The Universal tag class
22
    Universal = 0,
23
    /// The Application tag class
24
    Application = 1,
25
    /// The Context-Specific tag class
26
    ContextSpecific = 2,
27
    /// The Private tag class
28
    Private = 3,
29
  };
30
31
  /// An enum for representing ASN.1 Universal tag types
32
  enum class Asn1UniversalTagType : uint8_t
33
  {
34
    /// The reserved identifier for the End-of-Contents marker in an indefinite length encoding
35
    EndOfContent = 0,
36
    /// The universal tag type for Boolean
37
    Boolean = 1,
38
    /// The universal tag type for Integer
39
    Integer = 2,
40
    /// The universal tag type for Bit String
41
    BitString = 3,
42
    /// The universal tag type for Octet String
43
    OctetString = 4,
44
    /// The universal tag type for Null
45
    Null = 5,
46
    /// The universal tag type for Object Identifier
47
    ObjectIdentifier = 6,
48
    /// The universal tag type for Object Descriptor
49
    ObjectDescriptor = 7,
50
    /// The universal tag type for External
51
    External = 8,
52
    /// The universal tag type for Real
53
    Real = 9,
54
    /// The universal tag type for Enumerated
55
    Enumerated = 10,
56
    /// The universal tag type for Embedded-PDV
57
    EmbeddedPDV = 11,
58
    /// The universal tag type for UTF8 String
59
    UTF8String = 12,
60
    /// The universal tag type for Relative Object Identifier
61
    RelativeObjectIdentifier = 13,
62
    /// The universal tag type for Time
63
    Time = 14,
64
    /// A reserved value
65
    Reserved = 15,
66
    /// The universal tag type Sequence
67
    Sequence = 16,
68
    /// The universal tag type for Set
69
    Set = 17,
70
    /// The universal tag type for Numeric String
71
    NumericString = 18,
72
    /// The universal tag type for Printable String
73
    PrintableString = 19,
74
    /// The universal tag type for T61String
75
    T61String = 20,
76
    /// The universal tag type for Videotex String
77
    VideotexString = 21,
78
    /// The universal tag type for IA5String
79
    IA5String = 22,
80
    /// The universal tag type for UTC time
81
    UTCTime = 23,
82
    /// The universal tag type for Generalized time
83
    GeneralizedTime = 24,
84
    /// The universal tag type for GraphicString
85
    GraphicString = 25,
86
    /// The universal tag type for VisibleString
87
    VisibleString = 26,
88
    /// The universal tag type for GeneralString
89
    GeneralString = 27,
90
    /// The universal tag type for UniversalString
91
    UniversalString = 28,
92
    /// The universal tag type for CharacterString
93
    CharacterString = 29,
94
    /// The universal tag type for BMPString
95
    BMPString = 30,
96
    /// The universal tag type for Date
97
    Date = 31,
98
    /// The universal tag type for Time of Day
99
    TimeOfDay = 32,
100
    /// The universal tag type for Date-Time
101
    DateTime = 33,
102
    /// The universal tag type for Duration
103
    Duration = 34,
104
    /// The universal tag type for Object Identifier Internationalized Resource Identifier (IRI)
105
    ObjectIdentifierIRI = 35,
106
    /// The universal tag type for Relative Object Identifier Internationalized Resource Identifier (IRI)
107
    RelativeObjectIdentifierIRI = 36,
108
    /// A non-applicable value
109
    NotApplicable = 255
110
  };
111
112
  namespace internal
113
  {
114
    /// @enum Asn1LoadPolicy
115
    /// @brief Policy for when to evaluate (decode) ASN.1 record values.
116
    /// Determines whether the value is decoded immediately (eager) or on first access (lazy).
117
    enum class Asn1LoadPolicy
118
    {
119
      /// The value is evaluated on first access (lazy decoding).
120
      Lazy,
121
      /// The value is evaluated immediately on construction (eager decoding).
122
      Eager
123
    };
124
  }  // namespace internal
125
126
  /// @class Asn1Record
127
  /// Represents an ASN.1 record, as described in ITU-T Recommendation X.680:
128
  /// <https://www.itu.int/rec/T-REC-X.680/en>
129
  /// <https://en.wikipedia.org/wiki/ASN.1>
130
  class Asn1Record
131
  {
132
  public:
133
    /// A static method to decode a byte array into an Asn1Record
134
    /// @param data A byte array to decode
135
    /// @param dataLen The byte array length
136
    /// @param lazy Use lazy decoding, set to true by default. Lazy decoding entails delaying the decoding
137
    /// of the record value until it is accessed
138
    /// @return A smart pointer to the decoded ASN.1 record. If the byte stream is not a valid ASN.1 record
139
    /// an exception is thrown
140
    static std::unique_ptr<Asn1Record> decode(const uint8_t* data, size_t dataLen, bool lazy = true);
141
142
    /// Encode this record and convert it to a byte stream
143
    /// @return A vector of bytes representing the record
144
    std::vector<uint8_t> encode() const;
145
146
    /// @return The ASN.1 tag class
147
    Asn1TagClass getTagClass() const
148
0
    {
149
0
      return m_TagClass;
150
0
    }
151
152
    /// @return True if it's a constructed record, or false if it's a primitive record
153
    bool isConstructed() const
154
0
    {
155
0
      return m_IsConstructed;
156
0
    }
157
158
    /// @return The ASN.1 Universal tag type if the record is of class Universal, otherwise
159
    /// Asn1UniversalTagType#NotApplicable
160
    Asn1UniversalTagType getUniversalTagType() const;
161
162
    /// @return The ASN.1 tag type value
163
    uint8_t getTagType() const
164
65.1k
    {
165
65.1k
      return m_TagType;
166
65.1k
    }
167
168
    /// @return The length of the record value
169
    size_t getValueLength() const
170
0
    {
171
0
      return m_ValueLength;
172
0
    }
173
174
    /// @return The total length of the record
175
    size_t getTotalLength() const
176
684k
    {
177
684k
      return m_TotalLength;
178
684k
    }
179
180
    /// @return A string representation of the record
181
    std::string toString() const;
182
183
    /// A templated method that accepts a class derived from Asn1Record as its template argument and attempts
184
    /// to cast the current instance to that type
185
    /// @tparam Asn1RecordType The type to cast to
186
    /// @return A pointer to the type after casting
187
    template <class Asn1RecordType> Asn1RecordType* castAs()
188
108k
    {
189
108k
      auto result = dynamic_cast<Asn1RecordType*>(this);
190
108k
      if (result == nullptr)
191
1.78k
      {
192
1.78k
        throw std::bad_cast();
193
1.78k
      }
194
106k
      return result;
195
108k
    }
pcpp::Asn1SequenceRecord* pcpp::Asn1Record::castAs<pcpp::Asn1SequenceRecord>()
Line
Count
Source
188
78.2k
    {
189
78.2k
      auto result = dynamic_cast<Asn1RecordType*>(this);
190
78.2k
      if (result == nullptr)
191
1.62k
      {
192
1.62k
        throw std::bad_cast();
193
1.62k
      }
194
76.6k
      return result;
195
78.2k
    }
Unexecuted instantiation: pcpp::Asn1IntegerRecord* pcpp::Asn1Record::castAs<pcpp::Asn1IntegerRecord>()
Unexecuted instantiation: pcpp::Asn1ObjectIdentifierRecord* pcpp::Asn1Record::castAs<pcpp::Asn1ObjectIdentifierRecord>()
Unexecuted instantiation: pcpp::Asn1PrintableStringRecord* pcpp::Asn1Record::castAs<pcpp::Asn1PrintableStringRecord>()
Unexecuted instantiation: pcpp::Asn1IA5StringRecord* pcpp::Asn1Record::castAs<pcpp::Asn1IA5StringRecord>()
Unexecuted instantiation: pcpp::Asn1UTF8StringRecord* pcpp::Asn1Record::castAs<pcpp::Asn1UTF8StringRecord>()
Unexecuted instantiation: pcpp::Asn1SetRecord* pcpp::Asn1Record::castAs<pcpp::Asn1SetRecord>()
Unexecuted instantiation: pcpp::Asn1TimeRecord* pcpp::Asn1Record::castAs<pcpp::Asn1TimeRecord>()
Unexecuted instantiation: pcpp::Asn1BitStringRecord* pcpp::Asn1Record::castAs<pcpp::Asn1BitStringRecord>()
Unexecuted instantiation: pcpp::Asn1BooleanRecord* pcpp::Asn1Record::castAs<pcpp::Asn1BooleanRecord>()
pcpp::Asn1OctetStringRecord* pcpp::Asn1Record::castAs<pcpp::Asn1OctetStringRecord>()
Line
Count
Source
188
1.09k
    {
189
1.09k
      auto result = dynamic_cast<Asn1RecordType*>(this);
190
1.09k
      if (result == nullptr)
191
0
      {
192
0
        throw std::bad_cast();
193
0
      }
194
1.09k
      return result;
195
1.09k
    }
pcpp::Asn1ConstructedRecord* pcpp::Asn1Record::castAs<pcpp::Asn1ConstructedRecord>()
Line
Count
Source
188
23.4k
    {
189
23.4k
      auto result = dynamic_cast<Asn1RecordType*>(this);
190
23.4k
      if (result == nullptr)
191
152
      {
192
152
        throw std::bad_cast();
193
152
      }
194
23.2k
      return result;
195
23.4k
    }
pcpp::Asn1EnumeratedRecord* pcpp::Asn1Record::castAs<pcpp::Asn1EnumeratedRecord>()
Line
Count
Source
188
5.42k
    {
189
5.42k
      auto result = dynamic_cast<Asn1RecordType*>(this);
190
5.42k
      if (result == nullptr)
191
0
      {
192
0
        throw std::bad_cast();
193
0
      }
194
5.42k
      return result;
195
5.42k
    }
Unexecuted instantiation: pcpp::Asn1GenericRecord* pcpp::Asn1Record::castAs<pcpp::Asn1GenericRecord>()
196
197
374k
    virtual ~Asn1Record() = default;
198
199
  protected:
200
    Asn1TagClass m_TagClass = Asn1TagClass::Universal;
201
    bool m_IsConstructed = false;
202
    uint8_t m_TagType = 0;
203
204
    size_t m_ValueLength = 0;
205
    size_t m_TotalLength = 0;
206
207
374k
    Asn1Record() = default;
208
209
    /// @brief Decodes the record value from a byte array into the mutable cache variables.
210
    /// This method is marked as const as it can be called on a const instance of the record for lazy decoding.
211
    virtual void decodeValue(uint8_t const* data) const = 0;
212
213
    /// @brief Encodes the record value into a byte array
214
    /// Prefer using encodeValueSafe() to ensure the value is decoded first if needed
215
    virtual std::vector<uint8_t> encodeValue() const = 0;
216
217
    /// @brief Encodes the record value into a byte array, ensuring that the value is decoded first if needed
218
    std::vector<uint8_t> encodeValueSafe() const
219
0
    {
220
0
      decodeValueIfNeeded();
221
0
      return encodeValue();
222
0
    }
223
224
    static std::unique_ptr<Asn1Record> decodeTagAndCreateRecord(const uint8_t* data, size_t dataLen,
225
                                                                uint8_t& tagLen);
226
    uint8_t decodeLength(const uint8_t* data, size_t dataLen);
227
    void decodeValueIfNeeded() const;
228
229
    uint8_t encodeTag() const;
230
    std::vector<uint8_t> encodeLength() const;
231
232
    // note: Requires the value to be decoded first if lazy decoding is used
233
    virtual std::vector<std::string> toStringList() const;
234
235
    friend class Asn1ConstructedRecord;
236
237
  private:
238
    void setEncodedValue(uint8_t const* dataSource,
239
                         internal::Asn1LoadPolicy loadPolicy = internal::Asn1LoadPolicy::Lazy);
240
241
    mutable uint8_t const* m_EncodedValue = nullptr;
242
  };
243
244
  /// @class Asn1GenericRecord
245
  /// Represents a generic ASN.1 record, either of an unknown type or of a known type that doesn't
246
  /// have a dedicated parser yet
247
  class Asn1GenericRecord : public Asn1Record
248
  {
249
    friend class Asn1Record;
250
251
  public:
252
    /// A constructor to create a generic record
253
    /// @param tagClass The record tag class
254
    /// @param isConstructed A flag to indicate if the record is constructed or primitive
255
    /// @param tagType The record tag type value
256
    /// @param value A byte array of the tag value
257
    /// @param valueLen The length of the value byte array
258
    Asn1GenericRecord(Asn1TagClass tagClass, bool isConstructed, uint8_t tagType, const uint8_t* value,
259
                      size_t valueLen);
260
261
    /// A constructor to create a generic record
262
    /// @param tagClass The record tag class
263
    /// @param isConstructed A flag to indicate if the record is constructed or primitive
264
    /// @param tagType The record tag type value
265
    /// @param value A string representing the tag value
266
    Asn1GenericRecord(Asn1TagClass tagClass, bool isConstructed, uint8_t tagType, const std::string& value);
267
268
16.3k
    ~Asn1GenericRecord() override = default;
269
270
    /// @return A pointer to the tag value
271
    const uint8_t* getValue()
272
0
    {
273
0
      decodeValueIfNeeded();
274
0
      return m_Value.get();
275
0
    }
276
277
  protected:
278
16.3k
    Asn1GenericRecord() = default;
279
280
    void decodeValue(uint8_t const* data) const override;
281
    std::vector<uint8_t> encodeValue() const override;
282
283
  private:
284
    mutable std::unique_ptr<uint8_t[]> m_Value = nullptr;
285
286
    void init(Asn1TagClass tagClass, bool isConstructed, uint8_t tagType, const uint8_t* value, size_t valueLen);
287
  };
288
289
  /// @class Asn1ConstructedRecord
290
  /// Represents a constructed ASN.1 record, which is a record that has sub-records
291
  class Asn1ConstructedRecord : public Asn1Record
292
  {
293
    friend class Asn1Record;
294
295
  public:
296
    /// A constructor to create a constructed record
297
    /// @param tagClass The record tag class
298
    /// @param tagType The record tag type value
299
    /// @param subRecords A list of sub-records to assign as the record value
300
    explicit Asn1ConstructedRecord(Asn1TagClass tagClass, uint8_t tagType,
301
                                   const std::vector<Asn1Record*>& subRecords);
302
303
    /// A constructor to create a constructed record
304
    /// @param tagClass The record tag class
305
    /// @param tagType The record tag type value
306
    /// @param subRecords A PointerVector of sub-records to assign as the record value
307
    explicit Asn1ConstructedRecord(Asn1TagClass tagClass, uint8_t tagType,
308
                                   const PointerVector<Asn1Record>& subRecords);
309
310
    /// @return A reference to the list of sub-records. It's important to note that any modifications made to
311
    /// this list will directly affect the internal structure
312
    PointerVector<Asn1Record>& getSubRecords()
313
85.5k
    {
314
85.5k
      decodeValueIfNeeded();
315
85.5k
      return m_SubRecords;
316
85.5k
    };
317
318
  protected:
319
151k
    Asn1ConstructedRecord() = default;
320
321
    void decodeValue(uint8_t const* data) const override;
322
    std::vector<uint8_t> encodeValue() const override;
323
324
    std::vector<std::string> toStringList() const override;
325
326
    template <typename Iterator> void init(Asn1TagClass tagClass, uint8_t tagType, Iterator begin, Iterator end)
327
0
    {
328
0
      m_TagType = tagType;
329
0
      m_TagClass = tagClass;
330
0
      m_IsConstructed = true;
331
332
0
      size_t recordValueLength = 0;
333
0
      for (Iterator recordIter = begin; recordIter != end; ++recordIter)
334
0
      {
335
0
        auto encodedRecord = (*recordIter)->encode();
336
0
        auto copyRecord = Asn1Record::decode(encodedRecord.data(), encodedRecord.size(), LazySubRecordDecoding);
337
0
        m_SubRecords.pushBack(std::move(copyRecord));
338
0
        recordValueLength += encodedRecord.size();
339
0
      }
340
341
0
      m_ValueLength = recordValueLength;
342
0
      m_TotalLength = recordValueLength + 1 + (m_ValueLength < 128 ? 1 : 2);
343
0
    }
344
345
  private:
346
    // Set to false as there are issues with lazy decoding of sub-records in some cases.
347
    static constexpr bool LazySubRecordDecoding = false;
348
349
    mutable PointerVector<Asn1Record> m_SubRecords;
350
  };
351
352
  /// @class Asn1SequenceRecord
353
  /// Represents an ASN.1 record with a value of type Sequence
354
  class Asn1SequenceRecord : public Asn1ConstructedRecord
355
  {
356
    friend class Asn1Record;
357
358
  public:
359
    /// A constructor to create a record of type Sequence
360
    /// @param subRecords A list of sub-records to assign as the record value
361
    explicit Asn1SequenceRecord(const std::vector<Asn1Record*>& subRecords);
362
363
    /// A constructor to create a record of type Sequence
364
    /// @param subRecords A PointerVector of sub-records to assign as the record value
365
    explicit Asn1SequenceRecord(const PointerVector<Asn1Record>& subRecords);
366
367
  private:
368
75.1k
    Asn1SequenceRecord() = default;
369
  };
370
371
  /// @class Asn1SetRecord
372
  /// Represents an ASN.1 record with a value of type Set
373
  class Asn1SetRecord : public Asn1ConstructedRecord
374
  {
375
    friend class Asn1Record;
376
377
  public:
378
    /// A constructor to create a record of type Set
379
    /// @param subRecords A list of sub-records to assign as the record value
380
    explicit Asn1SetRecord(const std::vector<Asn1Record*>& subRecords);
381
382
    /// A constructor to create a record of type Set
383
    /// @param subRecords A PointerVector of sub-records to assign as the record value
384
    explicit Asn1SetRecord(const PointerVector<Asn1Record>& subRecords);
385
386
  private:
387
9.47k
    Asn1SetRecord() = default;
388
  };
389
390
  /// @class Asn1PrimitiveRecord
391
  /// Represents a primitive ASN.1 record, meaning a record that doesn't have sub-records.
392
  /// This is an abstract class that cannot be instantiated
393
  class Asn1PrimitiveRecord : public Asn1Record
394
  {
395
    friend class Asn1Record;
396
397
  protected:
398
87.9k
    Asn1PrimitiveRecord() = default;
399
    explicit Asn1PrimitiveRecord(Asn1UniversalTagType tagType);
400
  };
401
402
  /// @class Asn1IntegerRecord
403
  /// Represents an ASN.1 record with a value of type Integer
404
  class Asn1IntegerRecord : public Asn1PrimitiveRecord
405
  {
406
    friend class Asn1Record;
407
408
  public:
409
    template <typename T>
410
    using EnableIfUnsignedIntegral =
411
        std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value, int>;
412
413
    /// A constructor to create a record of type Integer
414
    /// @param value An integer to set as the record value
415
    explicit Asn1IntegerRecord(uint64_t value);
416
417
    /// A constructor to create a record of type Integer
418
    /// @param value An integer represented as a hex stream to set as the record value
419
    /// @throw std::invalid_argument if the value isn't a valid hex stream
420
    explicit Asn1IntegerRecord(const std::string& value);
421
422
    /// @return The integer value of this record
423
    /// @throw std::invalid_argument if the value doesn't fit the requested integer size
424
    template <typename T, EnableIfUnsignedIntegral<T> = 0> T getIntValue() const
425
5.42k
    {
426
5.42k
      decodeValueIfNeeded();
427
5.42k
      return m_Value.getInt<T>();
428
5.42k
    }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord11getIntValueIjTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS4_EE5valueEiE4typeELi0EEES4_v
_ZNK4pcpp17Asn1IntegerRecord11getIntValueIhTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS4_EE5valueEiE4typeELi0EEES4_v
Line
Count
Source
425
5.42k
    {
426
5.42k
      decodeValueIfNeeded();
427
5.42k
      return m_Value.getInt<T>();
428
5.42k
    }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord11getIntValueImTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS4_EE5valueEiE4typeELi0EEES4_v
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord11getIntValueItTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS4_EE5valueEiE4typeELi0EEES4_v
429
430
    /// @deprecated This method is deprecated, please use getIntValue()
431
    PCPP_DEPRECATED("Use getIntValue instead")
432
    uint32_t getValue()
433
0
    {
434
0
      return getIntValue<uint32_t>();
435
0
    }
436
437
    /// Get the integer value of this record as a hex string
438
    /// @param removeLeadingZeros If true, leading zeros will be removed
439
    /// @return A hex string representation of the record value
440
    std::string getValueAsString(bool removeLeadingZeros = false) const
441
0
    {
442
0
      decodeValueIfNeeded();
443
0
      return m_Value.toString(removeLeadingZeros);
444
0
    }
445
446
  protected:
447
82.4k
    Asn1IntegerRecord() = default;
448
449
    void decodeValue(uint8_t const* data) const override;
450
    std::vector<uint8_t> encodeValue() const override;
451
452
    std::vector<std::string> toStringList() const override;
453
454
  private:
455
    class BigInt
456
    {
457
    public:
458
82.4k
      BigInt() = default;
459
460
      template <typename T, EnableIfUnsignedIntegral<T> = 0> explicit BigInt(T value)
461
      {
462
        m_Value = initFromInt(value);
463
      }
464
465
      explicit BigInt(const std::string& value);
466
      BigInt(const BigInt& other);
467
468
      template <typename T, EnableIfUnsignedIntegral<T> = 0> BigInt& operator=(T value)
469
0
      {
470
0
        m_Value = initFromInt(value);
471
0
        return *this;
472
0
      }
473
      BigInt& operator=(const std::string& value);
474
      size_t size() const;
475
476
      template <typename T, EnableIfUnsignedIntegral<T> = 0> T getInt() const
477
5.42k
      {
478
5.42k
        if (!canFit<T>())
479
0
        {
480
0
          throw std::overflow_error("Value cannot fit into requested int type");
481
0
        }
482
483
5.42k
        std::stringstream sstream;
484
5.42k
        sstream << std::hex << m_Value;
485
486
5.42k
        uint64_t result;
487
5.42k
        sstream >> result;
488
5.42k
        return static_cast<T>(result);
489
5.42k
      }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6getIntIjTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEES5_v
_ZNK4pcpp17Asn1IntegerRecord6BigInt6getIntIhTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEES5_v
Line
Count
Source
477
5.42k
      {
478
5.42k
        if (!canFit<T>())
479
0
        {
480
0
          throw std::overflow_error("Value cannot fit into requested int type");
481
0
        }
482
483
5.42k
        std::stringstream sstream;
484
5.42k
        sstream << std::hex << m_Value;
485
486
5.42k
        uint64_t result;
487
5.42k
        sstream >> result;
488
5.42k
        return static_cast<T>(result);
489
5.42k
      }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6getIntImTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEES5_v
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6getIntItTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEES5_v
490
491
      template <typename T, EnableIfUnsignedIntegral<T> = 0> bool canFit() const
492
5.42k
      {
493
5.42k
        return sizeof(T) >= (m_Value.size() + 1) / 2;
494
5.42k
      }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6canFitIjTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEEbv
_ZNK4pcpp17Asn1IntegerRecord6BigInt6canFitIhTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEEbv
Line
Count
Source
492
5.42k
      {
493
5.42k
        return sizeof(T) >= (m_Value.size() + 1) / 2;
494
5.42k
      }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6canFitImTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEEbv
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6canFitItTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEEbv
495
496
      std::string toString(bool removeLeadingZeros = false) const;
497
      std::vector<uint8_t> toBytes() const;
498
499
    private:
500
      std::string m_Value;
501
502
      static std::string initFromString(const std::string& value);
503
504
      template <typename T, EnableIfUnsignedIntegral<T> = 0> static std::string initFromInt(T value)
505
0
      {
506
0
        std::stringstream ss;
507
0
        ss << std::hex << static_cast<uint64_t>(value);
508
0
        return ss.str();
509
0
      }
510
    };
511
512
    mutable BigInt m_Value;
513
  };
514
515
  /// @class Asn1EnumeratedRecord
516
  /// Represents an ASN.1 record with a value of type Enumerated
517
  class Asn1EnumeratedRecord : public Asn1IntegerRecord
518
  {
519
    friend class Asn1Record;
520
521
  public:
522
    /// A constructor to create a record of type Enumerated
523
    /// @param value An integer to set as the record value
524
    explicit Asn1EnumeratedRecord(uint32_t value);
525
526
  private:
527
20.7k
    Asn1EnumeratedRecord() = default;
528
  };
529
530
  /// @class Asn1StringRecord
531
  /// An abstract class for representing ASN.1 string records.
532
  /// This class is not instantiable, users should use the derived classes
533
  template <Asn1UniversalTagType TagType> class Asn1StringRecord : public Asn1PrimitiveRecord
534
  {
535
  public:
536
    /// @return The string value of this record
537
    std::string getValue() const
538
1.09k
    {
539
1.09k
      decodeValueIfNeeded();
540
1.09k
      return m_Value;
541
1.09k
    };
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)12>::getValue() const
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)19>::getValue() const
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)22>::getValue() const
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)4>::getValue() const
Line
Count
Source
538
1.09k
    {
539
1.09k
      decodeValueIfNeeded();
540
1.09k
      return m_Value;
541
1.09k
    };
542
543
  protected:
544
118k
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
545
118k
    {}
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)12>::Asn1StringRecord()
Line
Count
Source
544
133
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
545
133
    {}
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)19>::Asn1StringRecord()
Line
Count
Source
544
80
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
545
80
    {}
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)22>::Asn1StringRecord()
Line
Count
Source
544
34
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
545
34
    {}
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)4>::Asn1StringRecord()
Line
Count
Source
544
118k
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
545
118k
    {}
546
547
0
    explicit Asn1StringRecord(const std::string& value) : Asn1PrimitiveRecord(TagType), m_Value(value)
548
0
    {
549
0
      m_ValueLength = value.size();
550
0
      m_TotalLength = m_ValueLength + 2;
551
0
    }
552
553
    void decodeValue(uint8_t const* data) const override
554
104k
    {
555
104k
      m_Value = std::string(reinterpret_cast<char const*>(data), m_ValueLength);
556
104k
    }
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)4>::decodeValue(unsigned char const*) const
Line
Count
Source
554
104k
    {
555
104k
      m_Value = std::string(reinterpret_cast<char const*>(data), m_ValueLength);
556
104k
    }
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)12>::decodeValue(unsigned char const*) const
Line
Count
Source
554
83
    {
555
83
      m_Value = std::string(reinterpret_cast<char const*>(data), m_ValueLength);
556
83
    }
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)19>::decodeValue(unsigned char const*) const
Line
Count
Source
554
75
    {
555
75
      m_Value = std::string(reinterpret_cast<char const*>(data), m_ValueLength);
556
75
    }
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)22>::decodeValue(unsigned char const*) const
Line
Count
Source
554
27
    {
555
27
      m_Value = std::string(reinterpret_cast<char const*>(data), m_ValueLength);
556
27
    }
557
    std::vector<uint8_t> encodeValue() const override
558
0
    {
559
0
      return { m_Value.begin(), m_Value.end() };
560
0
    }
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)4>::encodeValue() const
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)12>::encodeValue() const
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)19>::encodeValue() const
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)22>::encodeValue() const
561
562
    std::vector<std::string> toStringList() const override
563
0
    {
564
0
      return { Asn1Record::toStringList().front() + ", Value: " + getValue() };
565
0
    }
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)4>::toStringList() const
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)12>::toStringList() const
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)19>::toStringList() const
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)22>::toStringList() const
566
567
    mutable std::string m_Value;
568
  };
569
570
  /// @class Asn1OctetStringRecord
571
  /// Represents an ASN.1 record with a value of type Octet String
572
  class Asn1OctetStringRecord : public Asn1StringRecord<Asn1UniversalTagType::OctetString>
573
  {
574
    friend class Asn1Record;
575
576
  public:
577
    using Asn1StringRecord::Asn1StringRecord;
578
579
    /// A constructor to create a record of type Octet String from a non-printable value
580
    /// @param value A byte array to set as the record value
581
    /// @param valueLength The length of the byte array
582
    explicit Asn1OctetStringRecord(const uint8_t* value, size_t valueLength);
583
584
    /// A constructor to create a record from a printable string value
585
    /// @param value A string to set as the record value
586
    explicit Asn1OctetStringRecord(const std::string& value) : Asn1StringRecord(value)
587
0
    {}
588
589
  protected:
590
    void decodeValue(uint8_t const* data) const override;
591
    std::vector<uint8_t> encodeValue() const override;
592
593
  private:
594
118k
    Asn1OctetStringRecord() = default;
595
596
    mutable bool m_IsPrintable = true;
597
  };
598
599
  /// @class Asn1UTF8StringRecord
600
  /// Represents an ASN.1 record with a value of type UTF8 String
601
  class Asn1UTF8StringRecord : public Asn1StringRecord<Asn1UniversalTagType::UTF8String>
602
  {
603
    friend class Asn1Record;
604
605
  public:
606
    /// A constructor to create a record from a printable string value
607
    /// @param value A string to set as the record value
608
    explicit Asn1UTF8StringRecord(const std::string& value) : Asn1StringRecord(value)
609
0
    {}
610
611
  private:
612
133
    Asn1UTF8StringRecord() = default;
613
  };
614
615
  /// @class Asn1PrintableStringRecord
616
  /// Represents an ASN.1 record with a value of type Printable String
617
  class Asn1PrintableStringRecord : public Asn1StringRecord<Asn1UniversalTagType::PrintableString>
618
  {
619
    friend class Asn1Record;
620
621
  public:
622
    /// A constructor to create a record from a printable string value
623
    /// @param value A string to set as the record value
624
    explicit Asn1PrintableStringRecord(const std::string& value) : Asn1StringRecord(value)
625
0
    {}
626
627
  private:
628
80
    Asn1PrintableStringRecord() = default;
629
  };
630
631
  /// @class Asn1IA5StringRecord
632
  /// Represents an ASN.1 record with a value of type IA5 String
633
  class Asn1IA5StringRecord : public Asn1StringRecord<Asn1UniversalTagType::IA5String>
634
  {
635
    friend class Asn1Record;
636
637
  public:
638
    /// A constructor to create a record from a printable string value
639
    /// @param value A string to set as the record value
640
    explicit Asn1IA5StringRecord(const std::string& value) : Asn1StringRecord(value)
641
0
    {}
642
643
  private:
644
34
    Asn1IA5StringRecord() = default;
645
  };
646
647
  /// @class Asn1BooleanRecord
648
  /// Represents an ASN.1 record with a value of type Boolean
649
  class Asn1BooleanRecord : public Asn1PrimitiveRecord
650
  {
651
    friend class Asn1Record;
652
653
  public:
654
    /// A constructor to create a record of type Boolean
655
    /// @param value A boolean to set as the record value
656
    explicit Asn1BooleanRecord(bool value);
657
658
    /// @return The boolean value of this record
659
    bool getValue() const
660
0
    {
661
0
      decodeValueIfNeeded();
662
0
      return m_Value;
663
0
    };
664
665
  protected:
666
    void decodeValue(uint8_t const* data) const override;
667
    std::vector<uint8_t> encodeValue() const override;
668
669
    std::vector<std::string> toStringList() const override;
670
671
  private:
672
4.25k
    Asn1BooleanRecord() = default;
673
674
    mutable bool m_Value = false;
675
  };
676
677
  /// @class Asn1NullRecord
678
  /// Represents an ASN.1 record with a value of type Null
679
  class Asn1NullRecord : public Asn1PrimitiveRecord
680
  {
681
    friend class Asn1Record;
682
683
  public:
684
    /// A constructor to create a record of type Null
685
    Asn1NullRecord();
686
687
  protected:
688
    void decodeValue(uint8_t const* data) const override
689
147
    {}
690
    std::vector<uint8_t> encodeValue() const override
691
0
    {
692
0
      return {};
693
0
    }
694
  };
695
696
  /// @class Asn1ObjectIdentifier
697
  /// Represents an ASN.1 Object Identifier (OID).
698
  class Asn1ObjectIdentifier
699
  {
700
    friend class Asn1ObjectIdentifierRecord;
701
702
  public:
703
    /// Construct an OID from an encoded byte buffer
704
    /// @param[in] data The byte buffer of the encoded OID data
705
    /// @param[in] dataLen The byte buffer size
706
    explicit Asn1ObjectIdentifier(const uint8_t* data, size_t dataLen);
707
708
    /// Construct an OID from its string representation (e.g., "1.2.840.113549").
709
    /// @param[in] oidString The string representation of the OID
710
    /// @throws std::invalid_argument if the string is malformed or contains invalid components
711
    explicit Asn1ObjectIdentifier(const std::string& oidString);
712
713
    /// @return A const reference to the internal vector of components
714
    const std::vector<uint32_t>& getComponents() const
715
0
    {
716
0
      return m_Components;
717
0
    }
718
719
    /// Equality operator to compare two OIDs
720
    /// @param[in] other Another Asn1ObjectIdentifier instance
721
    bool operator==(const Asn1ObjectIdentifier& other) const
722
0
    {
723
0
      return m_Components == other.m_Components;
724
0
    }
725
726
    /// Inequality operator to compare two OIDs
727
    /// @param[in] other Another Asn1ObjectIdentifier instance
728
    bool operator!=(const Asn1ObjectIdentifier& other) const
729
0
    {
730
0
      return m_Components != other.m_Components;
731
0
    }
732
733
    /// Convert the OID to its string representation (e.g., "1.2.840.113549")
734
    /// @return A string representing the OID
735
    std::string toString() const;
736
737
    /// Encode the OID to a byte buffer
738
    /// @return A byte buffer containing the encoded OID value
739
    std::vector<uint8_t> toBytes() const;
740
741
    friend std::ostream& operator<<(std::ostream& os, const Asn1ObjectIdentifier& oid)
742
0
    {
743
0
      return os << oid.toString();
744
0
    }
745
746
  protected:
747
647
    Asn1ObjectIdentifier() = default;
748
749
  private:
750
    std::vector<uint32_t> m_Components;
751
  };
752
753
  /// @class Asn1ObjectIdentifierRecord
754
  /// Represents an ASN.1 record with a value of type ObjectIdentifier
755
  class Asn1ObjectIdentifierRecord : public Asn1PrimitiveRecord
756
  {
757
    friend class Asn1Record;
758
759
  public:
760
    /// A constructor to create a ObjectIdentifier record
761
    /// @param[in] value The ObjectIdentifier (OID) to set as the record value
762
    explicit Asn1ObjectIdentifierRecord(const Asn1ObjectIdentifier& value);
763
764
    /// @return The OID value of this record
765
    const Asn1ObjectIdentifier& getValue() const
766
0
    {
767
0
      decodeValueIfNeeded();
768
0
      return m_Value;
769
0
    }
770
771
  protected:
772
    void decodeValue(uint8_t const* data) const override;
773
    std::vector<uint8_t> encodeValue() const override;
774
775
    std::vector<std::string> toStringList() const override;
776
777
  private:
778
    mutable Asn1ObjectIdentifier m_Value;
779
780
647
    Asn1ObjectIdentifierRecord() = default;
781
  };
782
783
  /// @class Asn1TimeRecord
784
  /// An abstract class for representing ASN.1 time records (UTCTime and GeneralizedTime).
785
  /// This class is not instantiable, users should use either Asn1UtcTimeRecord or Asn1GeneralizedTimeRecord
786
  class Asn1TimeRecord : public Asn1PrimitiveRecord
787
  {
788
  public:
789
    /// @param[in] timezone A timezone string - should be in the format of "Z" for UTC or +=HHMM for other
790
    /// timezones. The default value is UTC
791
    /// @return The time-point value of this record
792
    /// @throws std::invalid_argument if timezone is not in the correct format
793
    std::chrono::system_clock::time_point getValue(const std::string& timezone = "Z") const
794
0
    {
795
0
      decodeValueIfNeeded();
796
0
      return adjustTimezones(m_Value, "Z", timezone);
797
0
    };
798
799
    /// @param[in] format Requested value format
800
    /// @param[in] timezone A timezone string - should be in the format of "Z" for UTC or +=HHMM for other
801
    /// timezones. The default value is UTC
802
    /// @param[in] includeMilliseconds Should Include milliseconds in the returned string
803
    /// @return The value as string
804
    /// @throws std::invalid_argument if timezone is not in the correct format
805
    std::string getValueAsString(const std::string& format = "%Y-%m-%d %H:%M:%S", const std::string& timezone = "Z",
806
                                 bool includeMilliseconds = false) const;
807
808
  protected:
809
305
    Asn1TimeRecord() = default;
810
    explicit Asn1TimeRecord(Asn1UniversalTagType tagType, const std::chrono::system_clock::time_point& value,
811
                            const std::string& timezone);
812
813
    mutable std::chrono::system_clock::time_point m_Value;
814
815
    std::vector<std::string> toStringList() const override;
816
817
    static void validateTimezone(const std::string& timezone);
818
    static std::chrono::system_clock::time_point adjustTimezones(const std::chrono::system_clock::time_point& value,
819
                                                                 const std::string& fromTimezone,
820
                                                                 const std::string& toTimezone);
821
  };
822
823
  /// @class Asn1UtcTimeRecord
824
  /// Represents an ASN.1 record with a value of type UTCTime
825
  class Asn1UtcTimeRecord : public Asn1TimeRecord
826
  {
827
    friend class Asn1Record;
828
829
  public:
830
    /// A constructor to create a record of type UTC time
831
    /// @param[in] value A time-point to set as the record value
832
    /// @param[in] withSeconds Should write the ASN.1 record with second precision. The default is true
833
    explicit Asn1UtcTimeRecord(const std::chrono::system_clock::time_point& value, bool withSeconds = true);
834
835
  protected:
836
    void decodeValue(uint8_t const* data) const override;
837
    std::vector<uint8_t> encodeValue() const override;
838
839
  private:
840
40
    Asn1UtcTimeRecord() = default;
841
    mutable bool m_WithSeconds = true;
842
  };
843
844
  /// @class Asn1GeneralizedTimeRecord
845
  /// Represents an ASN.1 record with a value of type GeneralizedTime
846
  class Asn1GeneralizedTimeRecord : public Asn1TimeRecord
847
  {
848
    friend class Asn1Record;
849
850
  public:
851
    /// A constructor to create a record of type generalized time
852
    /// @param[in] value A time-point to set as the record value
853
    /// @param[in] timezone The time-point's timezone - should be in the format of "Z" for UTC or +=HHMM for other
854
    /// timezones. If not provided it's assumed the timezone is UTC
855
    /// @throws std::invalid_argument if timezone is not in the correct format
856
    explicit Asn1GeneralizedTimeRecord(const std::chrono::system_clock::time_point& value,
857
                                       const std::string& timezone = "Z");
858
859
  protected:
860
    void decodeValue(uint8_t const* data) const override;
861
    std::vector<uint8_t> encodeValue() const override;
862
863
  private:
864
265
    Asn1GeneralizedTimeRecord() = default;
865
    mutable std::string m_Timezone;
866
  };
867
868
  /// @class Asn1BitStringRecord
869
  /// Represents an ASN.1 record with a value of type BitString
870
  class Asn1BitStringRecord : public Asn1PrimitiveRecord
871
  {
872
    friend class Asn1Record;
873
874
  public:
875
    /// A constructor to create a record of type BitString
876
    /// @param value A bit string to set as the record value
877
    /// @throw std::invalid_argument if the string is not a valid bit string
878
    explicit Asn1BitStringRecord(const std::string& value);
879
880
    /// @return The bit string value of this record
881
    std::string getValue()
882
0
    {
883
0
      decodeValueIfNeeded();
884
0
      return m_Value.toString();
885
0
    };
886
887
    /// @return The byte vector value of this record
888
    std::vector<uint8_t> getVecValue()
889
0
    {
890
0
      decodeValueIfNeeded();
891
0
      return m_Value.toBytes();
892
0
    }
893
894
  protected:
895
    void decodeValue(uint8_t const* data) const override;
896
    std::vector<uint8_t> encodeValue() const override;
897
898
    std::vector<std::string> toStringList() const override;
899
900
  private:
901
    class BitSet
902
    {
903
    public:
904
272
      BitSet() = default;
905
      explicit BitSet(const std::string& value);
906
      BitSet(const uint8_t* data, size_t numBits);
907
908
      BitSet& operator=(const std::string& value);
909
910
      size_t sizeInBytes() const;
911
      std::string toString() const;
912
      std::vector<uint8_t> toBytes() const;
913
      size_t getNumBits() const
914
0
      {
915
0
        return m_NumBits;
916
0
      }
917
918
    private:
919
      void initFromString(const std::string& value);
920
921
      std::vector<std::bitset<8>> m_Data;
922
      size_t m_NumBits = 0;
923
    };
924
925
272
    Asn1BitStringRecord() = default;
926
927
    mutable BitSet m_Value;
928
  };
929
}  // namespace pcpp