Coverage Report

Created: 2025-08-26 07:54

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