Coverage Report

Created: 2026-09-28 07:37

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
71.1k
    {
165
71.1k
      return m_TagType;
166
71.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
815k
    {
177
815k
      return m_TotalLength;
178
815k
    }
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
119k
    {
189
119k
      auto result = dynamic_cast<Asn1RecordType*>(this);
190
119k
      if (result == nullptr)
191
2.39k
      {
192
2.39k
        throw std::bad_cast();
193
2.39k
      }
194
116k
      return result;
195
119k
    }
pcpp::Asn1SequenceRecord* pcpp::Asn1Record::castAs<pcpp::Asn1SequenceRecord>()
Line
Count
Source
188
88.2k
    {
189
88.2k
      auto result = dynamic_cast<Asn1RecordType*>(this);
190
88.2k
      if (result == nullptr)
191
1.95k
      {
192
1.95k
        throw std::bad_cast();
193
1.95k
      }
194
86.2k
      return result;
195
88.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.03k
    {
189
1.03k
      auto result = dynamic_cast<Asn1RecordType*>(this);
190
1.03k
      if (result == nullptr)
191
0
      {
192
0
        throw std::bad_cast();
193
0
      }
194
1.03k
      return result;
195
1.03k
    }
pcpp::Asn1ConstructedRecord* pcpp::Asn1Record::castAs<pcpp::Asn1ConstructedRecord>()
Line
Count
Source
188
24.3k
    {
189
24.3k
      auto result = dynamic_cast<Asn1RecordType*>(this);
190
24.3k
      if (result == nullptr)
191
440
      {
192
440
        throw std::bad_cast();
193
440
      }
194
23.9k
      return result;
195
24.3k
    }
pcpp::Asn1EnumeratedRecord* pcpp::Asn1Record::castAs<pcpp::Asn1EnumeratedRecord>()
Line
Count
Source
188
5.45k
    {
189
5.45k
      auto result = dynamic_cast<Asn1RecordType*>(this);
190
5.45k
      if (result == nullptr)
191
0
      {
192
0
        throw std::bad_cast();
193
0
      }
194
5.45k
      return result;
195
5.45k
    }
Unexecuted instantiation: pcpp::Asn1GenericRecord* pcpp::Asn1Record::castAs<pcpp::Asn1GenericRecord>()
196
197
452k
    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
452k
    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
36.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
36.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
95.3k
    {
314
95.3k
      decodeValueIfNeeded();
315
95.3k
      return m_SubRecords;
316
95.3k
    };
317
318
  protected:
319
178k
    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
89.4k
    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
15.0k
    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
103k
    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.45k
    {
426
5.45k
      decodeValueIfNeeded();
427
5.45k
      return m_Value.getInt<T>();
428
5.45k
    }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord11getIntValueIjTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS4_EE5valueEiE4typeELi0EEES4_v
_ZNK4pcpp17Asn1IntegerRecord11getIntValueIhTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS4_EE5valueEiE4typeELi0EEES4_v
Line
Count
Source
425
5.45k
    {
426
5.45k
      decodeValueIfNeeded();
427
5.45k
      return m_Value.getInt<T>();
428
5.45k
    }
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
91.9k
    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
91.9k
      BigInt() = default;
459
460
      template <typename T, EnableIfUnsignedIntegral<T> = 0>
461
      explicit BigInt(T value) : m_Value(initFromInt(value))
462
      {}
463
464
      explicit BigInt(const std::string& value);
465
      BigInt(const BigInt& other);
466
467
      template <typename T, EnableIfUnsignedIntegral<T> = 0> BigInt& operator=(T value)
468
0
      {
469
0
        m_Value = initFromInt(value);
470
0
        return *this;
471
0
      }
472
      BigInt& operator=(const std::string& value);
473
      size_t size() const;
474
475
      template <typename T, EnableIfUnsignedIntegral<T> = 0> T getInt() const
476
5.45k
      {
477
5.45k
        if (!canFit<T>())
478
0
        {
479
0
          throw std::overflow_error("Value cannot fit into requested int type");
480
0
        }
481
482
5.45k
        std::stringstream sstream;
483
5.45k
        sstream << std::hex << m_Value;
484
485
5.45k
        uint64_t result;
486
5.45k
        sstream >> result;
487
5.45k
        return static_cast<T>(result);
488
5.45k
      }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6getIntIjTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEES5_v
_ZNK4pcpp17Asn1IntegerRecord6BigInt6getIntIhTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEES5_v
Line
Count
Source
476
5.45k
      {
477
5.45k
        if (!canFit<T>())
478
0
        {
479
0
          throw std::overflow_error("Value cannot fit into requested int type");
480
0
        }
481
482
5.45k
        std::stringstream sstream;
483
5.45k
        sstream << std::hex << m_Value;
484
485
5.45k
        uint64_t result;
486
5.45k
        sstream >> result;
487
5.45k
        return static_cast<T>(result);
488
5.45k
      }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6getIntImTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEES5_v
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6getIntItTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEES5_v
489
490
      template <typename T, EnableIfUnsignedIntegral<T> = 0> bool canFit() const
491
5.45k
      {
492
5.45k
        return sizeof(T) >= (m_Value.size() + 1) / 2;
493
5.45k
      }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6canFitIjTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEEbv
_ZNK4pcpp17Asn1IntegerRecord6BigInt6canFitIhTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEEbv
Line
Count
Source
491
5.45k
      {
492
5.45k
        return sizeof(T) >= (m_Value.size() + 1) / 2;
493
5.45k
      }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6canFitImTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEEbv
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6canFitItTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEEbv
494
495
      std::string toString(bool removeLeadingZeros = false) const;
496
      std::vector<uint8_t> toBytes() const;
497
498
    private:
499
      std::string m_Value;
500
501
      static std::string initFromString(const std::string& value);
502
503
      template <typename T, EnableIfUnsignedIntegral<T> = 0> static std::string initFromInt(T value)
504
0
      {
505
0
        std::stringstream ss;
506
0
        ss << std::hex << static_cast<uint64_t>(value);
507
0
        return ss.str();
508
0
      }
509
    };
510
511
    mutable BigInt m_Value;
512
  };
513
514
  /// @class Asn1EnumeratedRecord
515
  /// Represents an ASN.1 record with a value of type Enumerated
516
  class Asn1EnumeratedRecord : public Asn1IntegerRecord
517
  {
518
    friend class Asn1Record;
519
520
  public:
521
    /// A constructor to create a record of type Enumerated
522
    /// @param value An integer to set as the record value
523
    explicit Asn1EnumeratedRecord(uint32_t value);
524
525
  private:
526
21.7k
    Asn1EnumeratedRecord() = default;
527
  };
528
529
  /// @class Asn1StringRecord
530
  /// An abstract class for representing ASN.1 string records.
531
  /// This class is not instantiable, users should use the derived classes
532
  template <Asn1UniversalTagType TagType> class Asn1StringRecord : public Asn1PrimitiveRecord
533
  {
534
  public:
535
    /// @return The string value of this record
536
    std::string getValue() const
537
1.03k
    {
538
1.03k
      decodeValueIfNeeded();
539
1.03k
      return m_Value;
540
1.03k
    };
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
537
1.03k
    {
538
1.03k
      decodeValueIfNeeded();
539
1.03k
      return m_Value;
540
1.03k
    };
541
542
  protected:
543
133k
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
544
133k
    {}
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)12>::Asn1StringRecord()
Line
Count
Source
543
69
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
544
69
    {}
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)19>::Asn1StringRecord()
Line
Count
Source
543
31
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
544
31
    {}
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)22>::Asn1StringRecord()
Line
Count
Source
543
87
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
544
87
    {}
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)4>::Asn1StringRecord()
Line
Count
Source
543
133k
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
544
133k
    {}
545
546
0
    explicit Asn1StringRecord(const std::string& value) : Asn1PrimitiveRecord(TagType), m_Value(value)
547
0
    {
548
0
      m_ValueLength = value.size();
549
0
      m_TotalLength = m_ValueLength + 2;
550
0
    }
551
552
    void decodeValue(uint8_t const* data) const override
553
120k
    {
554
120k
      m_Value = std::string(reinterpret_cast<char const*>(data), m_ValueLength);
555
120k
    }
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)4>::decodeValue(unsigned char const*) const
Line
Count
Source
553
120k
    {
554
120k
      m_Value = std::string(reinterpret_cast<char const*>(data), m_ValueLength);
555
120k
    }
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)12>::decodeValue(unsigned char const*) const
Line
Count
Source
553
69
    {
554
69
      m_Value = std::string(reinterpret_cast<char const*>(data), m_ValueLength);
555
69
    }
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)19>::decodeValue(unsigned char const*) const
Line
Count
Source
553
16
    {
554
16
      m_Value = std::string(reinterpret_cast<char const*>(data), m_ValueLength);
555
16
    }
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)22>::decodeValue(unsigned char const*) const
Line
Count
Source
553
87
    {
554
87
      m_Value = std::string(reinterpret_cast<char const*>(data), m_ValueLength);
555
87
    }
556
    std::vector<uint8_t> encodeValue() const override
557
0
    {
558
0
      return { m_Value.begin(), m_Value.end() };
559
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
560
561
    std::vector<std::string> toStringList() const override
562
0
    {
563
0
      return { Asn1Record::toStringList().front() + ", Value: " + getValue() };
564
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
565
566
    mutable std::string m_Value;
567
  };
568
569
  /// @class Asn1OctetStringRecord
570
  /// Represents an ASN.1 record with a value of type Octet String
571
  class Asn1OctetStringRecord : public Asn1StringRecord<Asn1UniversalTagType::OctetString>
572
  {
573
    friend class Asn1Record;
574
575
  public:
576
    using Asn1StringRecord::Asn1StringRecord;
577
578
    /// A constructor to create a record of type Octet String from a non-printable value
579
    /// @param value A byte array to set as the record value
580
    /// @param valueLength The length of the byte array
581
    explicit Asn1OctetStringRecord(const uint8_t* value, size_t valueLength);
582
583
    /// A constructor to create a record from a printable string value
584
    /// @param value A string to set as the record value
585
    explicit Asn1OctetStringRecord(const std::string& value) : Asn1StringRecord(value)
586
0
    {}
587
588
  protected:
589
    void decodeValue(uint8_t const* data) const override;
590
    std::vector<uint8_t> encodeValue() const override;
591
592
  private:
593
133k
    Asn1OctetStringRecord() = default;
594
595
    mutable bool m_IsPrintable = true;
596
  };
597
598
  /// @class Asn1UTF8StringRecord
599
  /// Represents an ASN.1 record with a value of type UTF8 String
600
  class Asn1UTF8StringRecord : public Asn1StringRecord<Asn1UniversalTagType::UTF8String>
601
  {
602
    friend class Asn1Record;
603
604
  public:
605
    /// A constructor to create a record from a printable string value
606
    /// @param value A string to set as the record value
607
    explicit Asn1UTF8StringRecord(const std::string& value) : Asn1StringRecord(value)
608
0
    {}
609
610
  private:
611
69
    Asn1UTF8StringRecord() = default;
612
  };
613
614
  /// @class Asn1PrintableStringRecord
615
  /// Represents an ASN.1 record with a value of type Printable String
616
  class Asn1PrintableStringRecord : public Asn1StringRecord<Asn1UniversalTagType::PrintableString>
617
  {
618
    friend class Asn1Record;
619
620
  public:
621
    /// A constructor to create a record from a printable string value
622
    /// @param value A string to set as the record value
623
    explicit Asn1PrintableStringRecord(const std::string& value) : Asn1StringRecord(value)
624
0
    {}
625
626
  private:
627
31
    Asn1PrintableStringRecord() = default;
628
  };
629
630
  /// @class Asn1IA5StringRecord
631
  /// Represents an ASN.1 record with a value of type IA5 String
632
  class Asn1IA5StringRecord : public Asn1StringRecord<Asn1UniversalTagType::IA5String>
633
  {
634
    friend class Asn1Record;
635
636
  public:
637
    /// A constructor to create a record from a printable string value
638
    /// @param value A string to set as the record value
639
    explicit Asn1IA5StringRecord(const std::string& value) : Asn1StringRecord(value)
640
0
    {}
641
642
  private:
643
87
    Asn1IA5StringRecord() = default;
644
  };
645
646
  /// @class Asn1BooleanRecord
647
  /// Represents an ASN.1 record with a value of type Boolean
648
  class Asn1BooleanRecord : public Asn1PrimitiveRecord
649
  {
650
    friend class Asn1Record;
651
652
  public:
653
    /// A constructor to create a record of type Boolean
654
    /// @param value A boolean to set as the record value
655
    explicit Asn1BooleanRecord(bool value);
656
657
    /// @return The boolean value of this record
658
    bool getValue() const
659
0
    {
660
0
      decodeValueIfNeeded();
661
0
      return m_Value;
662
0
    };
663
664
  protected:
665
    void decodeValue(uint8_t const* data) const override;
666
    std::vector<uint8_t> encodeValue() const override;
667
668
    std::vector<std::string> toStringList() const override;
669
670
  private:
671
9.66k
    Asn1BooleanRecord() = default;
672
673
    mutable bool m_Value = false;
674
  };
675
676
  /// @class Asn1NullRecord
677
  /// Represents an ASN.1 record with a value of type Null
678
  class Asn1NullRecord : public Asn1PrimitiveRecord
679
  {
680
    friend class Asn1Record;
681
682
  public:
683
    /// A constructor to create a record of type Null
684
    Asn1NullRecord();
685
686
  protected:
687
    void decodeValue(uint8_t const* data) const override
688
566
    {}
689
    std::vector<uint8_t> encodeValue() const override
690
0
    {
691
0
      return {};
692
0
    }
693
  };
694
695
  /// @class Asn1ObjectIdentifier
696
  /// Represents an ASN.1 Object Identifier (OID).
697
  class Asn1ObjectIdentifier
698
  {
699
    friend class Asn1ObjectIdentifierRecord;
700
701
  public:
702
    /// Construct an OID from an encoded byte buffer
703
    /// @param[in] data The byte buffer of the encoded OID data
704
    /// @param[in] dataLen The byte buffer size
705
    explicit Asn1ObjectIdentifier(const uint8_t* data, size_t dataLen);
706
707
    /// Construct an OID from its string representation (e.g., "1.2.840.113549").
708
    /// @param[in] oidString The string representation of the OID
709
    /// @throws std::invalid_argument if the string is malformed or contains invalid components
710
    explicit Asn1ObjectIdentifier(const std::string& oidString);
711
712
    /// @return A const reference to the internal vector of components
713
    const std::vector<uint32_t>& getComponents() const
714
0
    {
715
0
      return m_Components;
716
0
    }
717
718
    /// Equality operator to compare two OIDs
719
    /// @param[in] other Another Asn1ObjectIdentifier instance
720
    bool operator==(const Asn1ObjectIdentifier& other) const
721
0
    {
722
0
      return m_Components == other.m_Components;
723
0
    }
724
725
    /// Inequality operator to compare two OIDs
726
    /// @param[in] other Another Asn1ObjectIdentifier instance
727
    bool operator!=(const Asn1ObjectIdentifier& other) const
728
0
    {
729
0
      return m_Components != other.m_Components;
730
0
    }
731
732
    /// Convert the OID to its string representation (e.g., "1.2.840.113549")
733
    /// @return A string representing the OID
734
    std::string toString() const;
735
736
    /// Encode the OID to a byte buffer
737
    /// @return A byte buffer containing the encoded OID value
738
    std::vector<uint8_t> toBytes() const;
739
740
    friend std::ostream& operator<<(std::ostream& os, const Asn1ObjectIdentifier& oid)
741
0
    {
742
0
      return os << oid.toString();
743
0
    }
744
745
  protected:
746
1.20k
    Asn1ObjectIdentifier() = default;
747
748
  private:
749
    std::vector<uint32_t> m_Components;
750
  };
751
752
  /// @class Asn1ObjectIdentifierRecord
753
  /// Represents an ASN.1 record with a value of type ObjectIdentifier
754
  class Asn1ObjectIdentifierRecord : public Asn1PrimitiveRecord
755
  {
756
    friend class Asn1Record;
757
758
  public:
759
    /// A constructor to create a ObjectIdentifier record
760
    /// @param[in] value The ObjectIdentifier (OID) to set as the record value
761
    explicit Asn1ObjectIdentifierRecord(const Asn1ObjectIdentifier& value);
762
763
    /// @return The OID value of this record
764
    const Asn1ObjectIdentifier& getValue() const
765
0
    {
766
0
      decodeValueIfNeeded();
767
0
      return m_Value;
768
0
    }
769
770
  protected:
771
    void decodeValue(uint8_t const* data) const override;
772
    std::vector<uint8_t> encodeValue() const override;
773
774
    std::vector<std::string> toStringList() const override;
775
776
  private:
777
    mutable Asn1ObjectIdentifier m_Value;
778
779
1.20k
    Asn1ObjectIdentifierRecord() = default;
780
  };
781
782
  /// @class Asn1TimeRecord
783
  /// An abstract class for representing ASN.1 time records (UTCTime and GeneralizedTime).
784
  /// This class is not instantiable, users should use either Asn1UtcTimeRecord or Asn1GeneralizedTimeRecord
785
  class Asn1TimeRecord : public Asn1PrimitiveRecord
786
  {
787
  public:
788
    /// @param[in] timezone A timezone string - should be in the format of "Z" for UTC or +=HHMM for other
789
    /// timezones. The default value is UTC
790
    /// @return The time-point value of this record
791
    /// @throws std::invalid_argument if timezone is not in the correct format
792
    std::chrono::system_clock::time_point getValue(const std::string& timezone = "Z") const
793
0
    {
794
0
      decodeValueIfNeeded();
795
0
      return adjustTimezones(m_Value, "Z", timezone);
796
0
    };
797
798
    /// @param[in] format Requested value format
799
    /// @param[in] timezone A timezone string - should be in the format of "Z" for UTC or +=HHMM for other
800
    /// timezones. The default value is UTC
801
    /// @param[in] includeMilliseconds Should Include milliseconds in the returned string
802
    /// @return The value as string
803
    /// @throws std::invalid_argument if timezone is not in the correct format
804
    std::string getValueAsString(const std::string& format = "%Y-%m-%d %H:%M:%S", const std::string& timezone = "Z",
805
                                 bool includeMilliseconds = false) const;
806
807
  protected:
808
775
    Asn1TimeRecord() = default;
809
    explicit Asn1TimeRecord(Asn1UniversalTagType tagType, const std::chrono::system_clock::time_point& value,
810
                            const std::string& timezone);
811
812
    mutable std::chrono::system_clock::time_point m_Value;
813
814
    std::vector<std::string> toStringList() const override;
815
816
    static void validateTimezone(const std::string& timezone);
817
    static std::chrono::system_clock::time_point adjustTimezones(const std::chrono::system_clock::time_point& value,
818
                                                                 const std::string& fromTimezone,
819
                                                                 const std::string& toTimezone);
820
  };
821
822
  /// @class Asn1UtcTimeRecord
823
  /// Represents an ASN.1 record with a value of type UTCTime
824
  class Asn1UtcTimeRecord : public Asn1TimeRecord
825
  {
826
    friend class Asn1Record;
827
828
  public:
829
    /// A constructor to create a record of type UTC time
830
    /// @param[in] value A time-point to set as the record value
831
    /// @param[in] withSeconds Should write the ASN.1 record with second precision. The default is true
832
    explicit Asn1UtcTimeRecord(const std::chrono::system_clock::time_point& value, bool withSeconds = true);
833
834
  protected:
835
    void decodeValue(uint8_t const* data) const override;
836
    std::vector<uint8_t> encodeValue() const override;
837
838
  private:
839
105
    Asn1UtcTimeRecord() = default;
840
    mutable bool m_WithSeconds = true;
841
  };
842
843
  /// @class Asn1GeneralizedTimeRecord
844
  /// Represents an ASN.1 record with a value of type GeneralizedTime
845
  class Asn1GeneralizedTimeRecord : public Asn1TimeRecord
846
  {
847
    friend class Asn1Record;
848
849
  public:
850
    /// A constructor to create a record of type generalized time
851
    /// @param[in] value A time-point to set as the record value
852
    /// @param[in] timezone The time-point's timezone - should be in the format of "Z" for UTC or +=HHMM for other
853
    /// timezones. If not provided it's assumed the timezone is UTC
854
    /// @throws std::invalid_argument if timezone is not in the correct format
855
    explicit Asn1GeneralizedTimeRecord(const std::chrono::system_clock::time_point& value,
856
                                       const std::string& timezone = "Z");
857
858
  protected:
859
    void decodeValue(uint8_t const* data) const override;
860
    std::vector<uint8_t> encodeValue() const override;
861
862
  private:
863
670
    Asn1GeneralizedTimeRecord() = default;
864
    mutable std::string m_Timezone;
865
  };
866
867
  /// @class Asn1BitStringRecord
868
  /// Represents an ASN.1 record with a value of type BitString
869
  class Asn1BitStringRecord : public Asn1PrimitiveRecord
870
  {
871
    friend class Asn1Record;
872
873
  public:
874
    /// A constructor to create a record of type BitString
875
    /// @param value A bit string to set as the record value
876
    /// @throw std::invalid_argument if the string is not a valid bit string
877
    explicit Asn1BitStringRecord(const std::string& value);
878
879
    /// @return The bit string value of this record
880
    std::string getValue()
881
0
    {
882
0
      decodeValueIfNeeded();
883
0
      return m_Value.toString();
884
0
    };
885
886
    /// @return The byte vector value of this record
887
    std::vector<uint8_t> getVecValue()
888
0
    {
889
0
      decodeValueIfNeeded();
890
0
      return m_Value.toBytes();
891
0
    }
892
893
  protected:
894
    void decodeValue(uint8_t const* data) const override;
895
    std::vector<uint8_t> encodeValue() const override;
896
897
    std::vector<std::string> toStringList() const override;
898
899
  private:
900
    class BitSet
901
    {
902
    public:
903
189
      BitSet() = default;
904
      explicit BitSet(const std::string& value);
905
      BitSet(const uint8_t* data, size_t numBits);
906
907
      BitSet& operator=(const std::string& value);
908
909
      size_t sizeInBytes() const;
910
      std::string toString() const;
911
      std::vector<uint8_t> toBytes() const;
912
      size_t getNumBits() const
913
0
      {
914
0
        return m_NumBits;
915
0
      }
916
917
    private:
918
      void initFromString(const std::string& value);
919
920
      std::vector<std::bitset<8>> m_Data;
921
      size_t m_NumBits = 0;
922
    };
923
924
189
    Asn1BitStringRecord() = default;
925
926
    mutable BitSet m_Value;
927
  };
928
}  // namespace pcpp