Coverage Report

Created: 2025-07-18 07:14

/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
  /// @class Asn1Record
113
  /// Represents an ASN.1 record, as described in ITU-T Recommendation X.680:
114
  /// <https://www.itu.int/rec/T-REC-X.680/en>
115
  /// <https://en.wikipedia.org/wiki/ASN.1>
116
  class Asn1Record
117
  {
118
  public:
119
    /// A static method to decode a byte array into an Asn1Record
120
    /// @param data A byte array to decode
121
    /// @param dataLen The byte array length
122
    /// @param lazy Use lazy decoding, set to true by default. Lazy decoding entails delaying the decoding
123
    /// of the record value until it is accessed
124
    /// @return A smart pointer to the decoded ASN.1 record. If the byte stream is not a valid ASN.1 record
125
    /// an exception is thrown
126
    static std::unique_ptr<Asn1Record> decode(const uint8_t* data, size_t dataLen, bool lazy = true);
127
128
    /// Encode this record and convert it to a byte stream
129
    /// @return A vector of bytes representing the record
130
    std::vector<uint8_t> encode();
131
132
    /// @return The ASN.1 tag class
133
    Asn1TagClass getTagClass() const
134
0
    {
135
0
      return m_TagClass;
136
0
    }
137
138
    /// @return True if it's a constructed record, or false if it's a primitive record
139
    bool isConstructed() const
140
0
    {
141
0
      return m_IsConstructed;
142
0
    }
143
144
    /// @return The ASN.1 Universal tag type if the record is of class Universal, otherwise
145
    /// Asn1UniversalTagType#NotApplicable
146
    Asn1UniversalTagType getUniversalTagType() const;
147
148
    /// @return The ASN.1 tag type value
149
    uint8_t getTagType() const
150
44.3k
    {
151
44.3k
      return m_TagType;
152
44.3k
    }
153
154
    /// @return The length of the record value
155
    size_t getValueLength() const
156
0
    {
157
0
      return m_ValueLength;
158
0
    }
159
160
    /// @return The total length of the record
161
    size_t getTotalLength() const
162
216k
    {
163
216k
      return m_TotalLength;
164
216k
    }
165
166
    /// @return A string representation of the record
167
    std::string toString();
168
169
    /// A templated method that accepts a class derived from Asn1Record as its template argument and attempts
170
    /// to cast the current instance to that type
171
    /// @tparam Asn1RecordType The type to cast to
172
    /// @return A pointer to the type after casting
173
    template <class Asn1RecordType> Asn1RecordType* castAs()
174
78.8k
    {
175
78.8k
      auto result = dynamic_cast<Asn1RecordType*>(this);
176
78.8k
      if (result == nullptr)
177
1.19k
      {
178
1.19k
        throw std::bad_cast();
179
1.19k
      }
180
77.6k
      return result;
181
78.8k
    }
pcpp::Asn1SequenceRecord* pcpp::Asn1Record::castAs<pcpp::Asn1SequenceRecord>()
Line
Count
Source
174
54.0k
    {
175
54.0k
      auto result = dynamic_cast<Asn1RecordType*>(this);
176
54.0k
      if (result == nullptr)
177
1.05k
      {
178
1.05k
        throw std::bad_cast();
179
1.05k
      }
180
52.9k
      return result;
181
54.0k
    }
pcpp::Asn1ConstructedRecord* pcpp::Asn1Record::castAs<pcpp::Asn1ConstructedRecord>()
Line
Count
Source
174
18.6k
    {
175
18.6k
      auto result = dynamic_cast<Asn1RecordType*>(this);
176
18.6k
      if (result == nullptr)
177
144
      {
178
144
        throw std::bad_cast();
179
144
      }
180
18.4k
      return result;
181
18.6k
    }
Unexecuted instantiation: pcpp::Asn1IntegerRecord* pcpp::Asn1Record::castAs<pcpp::Asn1IntegerRecord>()
pcpp::Asn1OctetStringRecord* pcpp::Asn1Record::castAs<pcpp::Asn1OctetStringRecord>()
Line
Count
Source
174
988
    {
175
988
      auto result = dynamic_cast<Asn1RecordType*>(this);
176
988
      if (result == nullptr)
177
0
      {
178
0
        throw std::bad_cast();
179
0
      }
180
988
      return result;
181
988
    }
pcpp::Asn1EnumeratedRecord* pcpp::Asn1Record::castAs<pcpp::Asn1EnumeratedRecord>()
Line
Count
Source
174
5.21k
    {
175
5.21k
      auto result = dynamic_cast<Asn1RecordType*>(this);
176
5.21k
      if (result == nullptr)
177
0
      {
178
0
        throw std::bad_cast();
179
0
      }
180
5.21k
      return result;
181
5.21k
    }
Unexecuted instantiation: pcpp::Asn1GenericRecord* pcpp::Asn1Record::castAs<pcpp::Asn1GenericRecord>()
Unexecuted instantiation: pcpp::Asn1BooleanRecord* pcpp::Asn1Record::castAs<pcpp::Asn1BooleanRecord>()
Unexecuted instantiation: pcpp::Asn1SetRecord* pcpp::Asn1Record::castAs<pcpp::Asn1SetRecord>()
182
183
125k
    virtual ~Asn1Record() = default;
184
185
  protected:
186
    Asn1TagClass m_TagClass = Asn1TagClass::Universal;
187
    bool m_IsConstructed = false;
188
    uint8_t m_TagType = 0;
189
190
    size_t m_ValueLength = 0;
191
    size_t m_TotalLength = 0;
192
193
    uint8_t* m_EncodedValue = nullptr;
194
195
125k
    Asn1Record() = default;
196
197
    static std::unique_ptr<Asn1Record> decodeInternal(const uint8_t* data, size_t dataLen, bool lazy);
198
199
    virtual void decodeValue(uint8_t* data, bool lazy) = 0;
200
    virtual std::vector<uint8_t> encodeValue() const = 0;
201
202
    static std::unique_ptr<Asn1Record> decodeTagAndCreateRecord(const uint8_t* data, size_t dataLen,
203
                                                                uint8_t& tagLen);
204
    uint8_t decodeLength(const uint8_t* data, size_t dataLen);
205
    void decodeValueIfNeeded();
206
207
    uint8_t encodeTag();
208
    std::vector<uint8_t> encodeLength() const;
209
210
    virtual std::vector<std::string> toStringList();
211
212
    friend class Asn1ConstructedRecord;
213
  };
214
215
  /// @class Asn1GenericRecord
216
  /// Represents a generic ASN.1 record, either of an unknown type or of a known type that doesn't
217
  /// have a dedicated parser yet
218
  class Asn1GenericRecord : public Asn1Record
219
  {
220
    friend class Asn1Record;
221
222
  public:
223
    /// A constructor to create a generic record
224
    /// @param tagClass The record tag class
225
    /// @param isConstructed A flag to indicate if the record is constructed or primitive
226
    /// @param tagType The record tag type value
227
    /// @param value A byte array of the tag value
228
    /// @param valueLen The length of the value byte array
229
    Asn1GenericRecord(Asn1TagClass tagClass, bool isConstructed, uint8_t tagType, const uint8_t* value,
230
                      size_t valueLen);
231
232
    /// A constructor to create a generic record
233
    /// @param tagClass The record tag class
234
    /// @param isConstructed A flag to indicate if the record is constructed or primitive
235
    /// @param tagType The record tag type value
236
    /// @param value A string representing the tag value
237
    Asn1GenericRecord(Asn1TagClass tagClass, bool isConstructed, uint8_t tagType, const std::string& value);
238
239
    ~Asn1GenericRecord() override;
240
241
    /// @return A pointer to the tag value
242
    const uint8_t* getValue()
243
0
    {
244
0
      decodeValueIfNeeded();
245
0
      return m_Value;
246
0
    }
247
248
  protected:
249
4.10k
    Asn1GenericRecord() = default;
250
251
    void decodeValue(uint8_t* data, bool lazy) override;
252
    std::vector<uint8_t> encodeValue() const override;
253
254
  private:
255
    uint8_t* m_Value = nullptr;
256
257
    void init(Asn1TagClass tagClass, bool isConstructed, uint8_t tagType, const uint8_t* value, size_t valueLen);
258
  };
259
260
  /// @class Asn1ConstructedRecord
261
  /// Represents a constructed ASN.1 record, which is a record that has sub-records
262
  class Asn1ConstructedRecord : public Asn1Record
263
  {
264
    friend class Asn1Record;
265
266
  public:
267
    /// A constructor to create a constructed record
268
    /// @param tagClass The record tag class
269
    /// @param tagType The record tag type value
270
    /// @param subRecords A list of sub-records to assign as the record value
271
    explicit Asn1ConstructedRecord(Asn1TagClass tagClass, uint8_t tagType,
272
                                   const std::vector<Asn1Record*>& subRecords);
273
274
    /// A constructor to create a constructed record
275
    /// @param tagClass The record tag class
276
    /// @param tagType The record tag type value
277
    /// @param subRecords A PointerVector of sub-records to assign as the record value
278
    explicit Asn1ConstructedRecord(Asn1TagClass tagClass, uint8_t tagType,
279
                                   const PointerVector<Asn1Record>& subRecords);
280
281
    /// @return A reference to the list of sub-records. It's important to note that any modifications made to
282
    /// this list will directly affect the internal structure
283
    PointerVector<Asn1Record>& getSubRecords()
284
61.3k
    {
285
61.3k
      decodeValueIfNeeded();
286
61.3k
      return m_SubRecords;
287
61.3k
    };
288
289
  protected:
290
75.0k
    Asn1ConstructedRecord() = default;
291
292
    void decodeValue(uint8_t* data, bool lazy) override;
293
    std::vector<uint8_t> encodeValue() const override;
294
295
    std::vector<std::string> toStringList() override;
296
297
    template <typename Iterator> void init(Asn1TagClass tagClass, uint8_t tagType, Iterator begin, Iterator end)
298
0
    {
299
0
      m_TagType = tagType;
300
0
      m_TagClass = tagClass;
301
0
      m_IsConstructed = true;
302
303
0
      size_t recordValueLength = 0;
304
0
      for (Iterator recordIter = begin; recordIter != end; ++recordIter)
305
0
      {
306
0
        auto encodedRecord = (*recordIter)->encode();
307
0
        auto copyRecord = Asn1Record::decode(encodedRecord.data(), encodedRecord.size(), false);
308
0
        m_SubRecords.pushBack(std::move(copyRecord));
309
0
        recordValueLength += encodedRecord.size();
310
0
      }
311
312
0
      m_ValueLength = recordValueLength;
313
0
      m_TotalLength = recordValueLength + 1 + (m_ValueLength < 128 ? 1 : 2);
314
0
    }
315
316
  private:
317
    PointerVector<Asn1Record> m_SubRecords;
318
  };
319
320
  /// @class Asn1SequenceRecord
321
  /// Represents an ASN.1 record with a value of type Sequence
322
  class Asn1SequenceRecord : public Asn1ConstructedRecord
323
  {
324
    friend class Asn1Record;
325
326
  public:
327
    /// A constructor to create a record of type Sequence
328
    /// @param subRecords A list of sub-records to assign as the record value
329
    explicit Asn1SequenceRecord(const std::vector<Asn1Record*>& subRecords);
330
331
    /// A constructor to create a record of type Sequence
332
    /// @param subRecords A PointerVector of sub-records to assign as the record value
333
    explicit Asn1SequenceRecord(const PointerVector<Asn1Record>& subRecords);
334
335
  private:
336
35.0k
    Asn1SequenceRecord() = default;
337
  };
338
339
  /// @class Asn1SetRecord
340
  /// Represents an ASN.1 record with a value of type Set
341
  class Asn1SetRecord : public Asn1ConstructedRecord
342
  {
343
    friend class Asn1Record;
344
345
  public:
346
    /// A constructor to create a record of type Set
347
    /// @param subRecords A list of sub-records to assign as the record value
348
    explicit Asn1SetRecord(const std::vector<Asn1Record*>& subRecords);
349
350
    /// A constructor to create a record of type Set
351
    /// @param subRecords A PointerVector of sub-records to assign as the record value
352
    explicit Asn1SetRecord(const PointerVector<Asn1Record>& subRecords);
353
354
  private:
355
307
    Asn1SetRecord() = default;
356
  };
357
358
  /// @class Asn1PrimitiveRecord
359
  /// Represents a primitive ASN.1 record, meaning a record that doesn't have sub-records.
360
  /// This is an abstract class that cannot be instantiated
361
  class Asn1PrimitiveRecord : public Asn1Record
362
  {
363
    friend class Asn1Record;
364
365
  protected:
366
40.4k
    Asn1PrimitiveRecord() = default;
367
    explicit Asn1PrimitiveRecord(Asn1UniversalTagType tagType);
368
  };
369
370
  /// @class Asn1IntegerRecord
371
  /// Represents an ASN.1 record with a value of type Integer
372
  class Asn1IntegerRecord : public Asn1PrimitiveRecord
373
  {
374
    friend class Asn1Record;
375
376
  public:
377
    template <typename T>
378
    using EnableIfUnsignedIntegral =
379
        std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value, int>;
380
381
    /// A constructor to create a record of type Integer
382
    /// @param value An integer to set as the record value
383
    explicit Asn1IntegerRecord(uint64_t value);
384
385
    /// A constructor to create a record of type Integer
386
    /// @param value An integer represented as a hex stream to set as the record value
387
    /// @throw std::invalid_argument if the value isn't a valid hex stream
388
    explicit Asn1IntegerRecord(const std::string& value);
389
390
    /// @return The integer value of this record
391
    /// @throw std::invalid_argument if the value doesn't fit the requested integer size
392
    template <typename T, EnableIfUnsignedIntegral<T> = 0> T getIntValue()
393
5.21k
    {
394
5.21k
      decodeValueIfNeeded();
395
5.21k
      return m_Value.getInt<T>();
396
5.21k
    }
Unexecuted instantiation: _ZN4pcpp17Asn1IntegerRecord11getIntValueIjTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS4_EE5valueEiE4typeELi0EEES4_v
Unexecuted instantiation: _ZN4pcpp17Asn1IntegerRecord11getIntValueImTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS4_EE5valueEiE4typeELi0EEES4_v
Unexecuted instantiation: _ZN4pcpp17Asn1IntegerRecord11getIntValueItTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS4_EE5valueEiE4typeELi0EEES4_v
_ZN4pcpp17Asn1IntegerRecord11getIntValueIhTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS4_EE5valueEiE4typeELi0EEES4_v
Line
Count
Source
393
5.21k
    {
394
5.21k
      decodeValueIfNeeded();
395
5.21k
      return m_Value.getInt<T>();
396
5.21k
    }
397
398
    /// @deprecated This method is deprecated, please use getIntValue()
399
    PCPP_DEPRECATED("Use getIntValue instead")
400
    uint32_t getValue()
401
0
    {
402
0
      return getIntValue<uint32_t>();
403
0
    }
404
405
    /// @return A hex string representation of the record value
406
    std::string getValueAsString()
407
0
    {
408
0
      decodeValueIfNeeded();
409
0
      return m_Value.toString();
410
0
    }
411
412
  protected:
413
39.1k
    Asn1IntegerRecord() = default;
414
415
    void decodeValue(uint8_t* data, bool lazy) override;
416
    std::vector<uint8_t> encodeValue() const override;
417
418
    std::vector<std::string> toStringList() override;
419
420
  private:
421
    class BigInt
422
    {
423
    public:
424
39.1k
      BigInt() = default;
425
426
      template <typename T, EnableIfUnsignedIntegral<T> = 0> explicit BigInt(T value)
427
      {
428
        m_Value = initFromInt(value);
429
      }
430
431
      explicit BigInt(const std::string& value);
432
      BigInt(const BigInt& other);
433
434
      template <typename T, EnableIfUnsignedIntegral<T> = 0> BigInt& operator=(T value)
435
0
      {
436
0
        m_Value = initFromInt(value);
437
0
        return *this;
438
0
      }
439
      BigInt& operator=(const std::string& value);
440
      size_t size() const;
441
442
      template <typename T, EnableIfUnsignedIntegral<T> = 0> T getInt() const
443
5.21k
      {
444
5.21k
        if (!canFit<T>())
445
0
        {
446
0
          throw std::overflow_error("Value cannot fit into requested int type");
447
0
        }
448
449
5.21k
        std::stringstream sstream;
450
5.21k
        sstream << std::hex << m_Value;
451
452
5.21k
        uint64_t result;
453
5.21k
        sstream >> result;
454
5.21k
        return static_cast<T>(result);
455
5.21k
      }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6getIntIjTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEES5_v
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6getIntImTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEES5_v
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6getIntItTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEES5_v
_ZNK4pcpp17Asn1IntegerRecord6BigInt6getIntIhTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEES5_v
Line
Count
Source
443
5.21k
      {
444
5.21k
        if (!canFit<T>())
445
0
        {
446
0
          throw std::overflow_error("Value cannot fit into requested int type");
447
0
        }
448
449
5.21k
        std::stringstream sstream;
450
5.21k
        sstream << std::hex << m_Value;
451
452
5.21k
        uint64_t result;
453
5.21k
        sstream >> result;
454
5.21k
        return static_cast<T>(result);
455
5.21k
      }
456
457
      template <typename T, EnableIfUnsignedIntegral<T> = 0> bool canFit() const
458
5.21k
      {
459
5.21k
        return sizeof(T) >= (m_Value.size() + 1) / 2;
460
5.21k
      }
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6canFitIjTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEEbv
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6canFitImTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEEbv
Unexecuted instantiation: _ZNK4pcpp17Asn1IntegerRecord6BigInt6canFitItTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEEbv
_ZNK4pcpp17Asn1IntegerRecord6BigInt6canFitIhTnNSt3__19enable_ifIXaasr3std11is_integralIT_EE5valuesr3std11is_unsignedIS5_EE5valueEiE4typeELi0EEEbv
Line
Count
Source
458
5.21k
      {
459
5.21k
        return sizeof(T) >= (m_Value.size() + 1) / 2;
460
5.21k
      }
461
462
      std::string toString() const;
463
      std::vector<uint8_t> toBytes() const;
464
465
    private:
466
      std::string m_Value;
467
468
      static std::string initFromString(const std::string& value);
469
470
      template <typename T, EnableIfUnsignedIntegral<T> = 0> static std::string initFromInt(T value)
471
0
      {
472
0
        std::stringstream ss;
473
0
        ss << std::hex << static_cast<uint64_t>(value);
474
0
        return ss.str();
475
0
      }
476
    };
477
478
    BigInt m_Value;
479
  };
480
481
  /// @class Asn1EnumeratedRecord
482
  /// Represents an ASN.1 record with a value of type Enumerated
483
  class Asn1EnumeratedRecord : public Asn1IntegerRecord
484
  {
485
    friend class Asn1Record;
486
487
  public:
488
    /// A constructor to create a record of type Enumerated
489
    /// @param value An integer to set as the record value
490
    explicit Asn1EnumeratedRecord(uint32_t value);
491
492
  private:
493
3.48k
    Asn1EnumeratedRecord() = default;
494
  };
495
496
  /// @class Asn1StringRecord
497
  /// An abstract class for representing ASN.1 string records.
498
  /// This class is not instantiable, users should use the derived classes
499
  template <Asn1UniversalTagType TagType> class Asn1StringRecord : public Asn1PrimitiveRecord
500
  {
501
  public:
502
    /// @return The string value of this record
503
    std::string getValue()
504
988
    {
505
988
      decodeValueIfNeeded();
506
988
      return m_Value;
507
988
    };
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)12>::getValue()
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)19>::getValue()
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)22>::getValue()
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)4>::getValue()
Line
Count
Source
504
988
    {
505
988
      decodeValueIfNeeded();
506
988
      return m_Value;
507
988
    };
508
509
  protected:
510
5.93k
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
511
5.93k
    {}
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)12>::Asn1StringRecord()
Line
Count
Source
510
5
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
511
5
    {}
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)19>::Asn1StringRecord()
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)22>::Asn1StringRecord()
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)4>::Asn1StringRecord()
Line
Count
Source
510
5.92k
    Asn1StringRecord() : Asn1PrimitiveRecord(TagType)
511
5.92k
    {}
512
513
0
    explicit Asn1StringRecord(const std::string& value) : Asn1PrimitiveRecord(TagType), m_Value(value)
514
0
    {
515
0
      m_ValueLength = value.size();
516
0
      m_TotalLength = m_ValueLength + 2;
517
0
    }
518
519
    void decodeValue(uint8_t* data, bool lazy) override
520
475
    {
521
475
      m_Value = std::string(reinterpret_cast<char*>(data), m_ValueLength);
522
475
    }
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)12>::decodeValue(unsigned char*, bool)
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)19>::decodeValue(unsigned char*, bool)
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)22>::decodeValue(unsigned char*, bool)
pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)4>::decodeValue(unsigned char*, bool)
Line
Count
Source
520
475
    {
521
475
      m_Value = std::string(reinterpret_cast<char*>(data), m_ValueLength);
522
475
    }
523
    std::vector<uint8_t> encodeValue() const override
524
0
    {
525
0
      return { m_Value.begin(), m_Value.end() };
526
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
527
528
    std::vector<std::string> toStringList() override
529
0
    {
530
0
      return { Asn1Record::toStringList().front() + ", Value: " + getValue() };
531
0
    }
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)4>::toStringList()
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)12>::toStringList()
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)19>::toStringList()
Unexecuted instantiation: pcpp::Asn1StringRecord<(pcpp::Asn1UniversalTagType)22>::toStringList()
532
533
    std::string m_Value;
534
  };
535
536
  /// @class Asn1OctetStringRecord
537
  /// Represents an ASN.1 record with a value of type Octet String
538
  class Asn1OctetStringRecord : public Asn1StringRecord<Asn1UniversalTagType::OctetString>
539
  {
540
    friend class Asn1Record;
541
542
  public:
543
    using Asn1StringRecord::Asn1StringRecord;
544
545
    /// A constructor to create a record of type Octet String from a non-printable value
546
    /// @param value A byte array to set as the record value
547
    /// @param valueLength The length of the byte array
548
    explicit Asn1OctetStringRecord(const uint8_t* value, size_t valueLength);
549
550
    /// A constructor to create a record from a printable string value
551
    /// @param value A string to set as the record value
552
    explicit Asn1OctetStringRecord(const std::string& value) : Asn1StringRecord(value)
553
0
    {}
554
555
  protected:
556
    void decodeValue(uint8_t* data, bool lazy) override;
557
    std::vector<uint8_t> encodeValue() const override;
558
559
  private:
560
5.92k
    Asn1OctetStringRecord() = default;
561
562
    bool m_IsPrintable = true;
563
  };
564
565
  /// @class Asn1UTF8StringRecord
566
  /// Represents an ASN.1 record with a value of type UTF8 String
567
  class Asn1UTF8StringRecord : public Asn1StringRecord<Asn1UniversalTagType::UTF8String>
568
  {
569
    friend class Asn1Record;
570
571
  public:
572
    /// A constructor to create a record from a printable string value
573
    /// @param value A string to set as the record value
574
    explicit Asn1UTF8StringRecord(const std::string& value) : Asn1StringRecord(value)
575
0
    {}
576
577
  private:
578
5
    Asn1UTF8StringRecord() = default;
579
  };
580
581
  /// @class Asn1PrintableStringRecord
582
  /// Represents an ASN.1 record with a value of type Printable String
583
  class Asn1PrintableStringRecord : public Asn1StringRecord<Asn1UniversalTagType::PrintableString>
584
  {
585
    friend class Asn1Record;
586
587
  public:
588
    /// A constructor to create a record from a printable string value
589
    /// @param value A string to set as the record value
590
    explicit Asn1PrintableStringRecord(const std::string& value) : Asn1StringRecord(value)
591
0
    {}
592
593
  private:
594
0
    Asn1PrintableStringRecord() = default;
595
  };
596
597
  /// @class Asn1IA5StringRecord
598
  /// Represents an ASN.1 record with a value of type IA5 String
599
  class Asn1IA5StringRecord : public Asn1StringRecord<Asn1UniversalTagType::IA5String>
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 Asn1IA5StringRecord(const std::string& value) : Asn1StringRecord(value)
607
0
    {}
608
609
  private:
610
0
    Asn1IA5StringRecord() = default;
611
  };
612
613
  /// @class Asn1BooleanRecord
614
  /// Represents an ASN.1 record with a value of type Boolean
615
  class Asn1BooleanRecord : public Asn1PrimitiveRecord
616
  {
617
    friend class Asn1Record;
618
619
  public:
620
    /// A constructor to create a record of type Boolean
621
    /// @param value A boolean to set as the record value
622
    explicit Asn1BooleanRecord(bool value);
623
624
    /// @return The boolean value of this record
625
    bool getValue()
626
0
    {
627
0
      decodeValueIfNeeded();
628
0
      return m_Value;
629
0
    };
630
631
  protected:
632
    void decodeValue(uint8_t* data, bool lazy) override;
633
    std::vector<uint8_t> encodeValue() const override;
634
635
    std::vector<std::string> toStringList() override;
636
637
  private:
638
683
    Asn1BooleanRecord() = default;
639
640
    bool m_Value = false;
641
  };
642
643
  /// @class Asn1NullRecord
644
  /// Represents an ASN.1 record with a value of type Null
645
  class Asn1NullRecord : public Asn1PrimitiveRecord
646
  {
647
    friend class Asn1Record;
648
649
  public:
650
    /// A constructor to create a record of type Null
651
    Asn1NullRecord();
652
653
  protected:
654
    void decodeValue(uint8_t* data, bool lazy) override
655
0
    {}
656
    std::vector<uint8_t> encodeValue() const override
657
0
    {
658
0
      return {};
659
0
    }
660
  };
661
662
  /// @class Asn1ObjectIdentifier
663
  /// Represents an ASN.1 Object Identifier (OID).
664
  class Asn1ObjectIdentifier
665
  {
666
    friend class Asn1ObjectIdentifierRecord;
667
668
  public:
669
    /// Construct an OID from an encoded byte buffer
670
    /// @param[in] data The byte buffer of the encoded OID data
671
    /// @param[in] dataLen The byte buffer size
672
    explicit Asn1ObjectIdentifier(const uint8_t* data, size_t dataLen);
673
674
    /// Construct an OID from its string representation (e.g., "1.2.840.113549").
675
    /// @param[in] oidString The string representation of the OID
676
    /// @throws std::invalid_argument if the string is malformed or contains invalid components
677
    explicit Asn1ObjectIdentifier(const std::string& oidString);
678
679
    /// @return A const reference to the internal vector of components
680
    const std::vector<uint32_t>& getComponents() const
681
0
    {
682
0
      return m_Components;
683
0
    }
684
685
    /// Equality operator to compare two OIDs
686
    /// @param[in] other Another Asn1ObjectIdentifier instance
687
    bool operator==(const Asn1ObjectIdentifier& other) const
688
0
    {
689
0
      return m_Components == other.m_Components;
690
0
    }
691
692
    /// Inequality operator to compare two OIDs
693
    /// @param[in] other Another Asn1ObjectIdentifier instance
694
    bool operator!=(const Asn1ObjectIdentifier& other) const
695
0
    {
696
0
      return m_Components != other.m_Components;
697
0
    }
698
699
    /// Convert the OID to its string representation (e.g., "1.2.840.113549")
700
    /// @return A string representing the OID
701
    std::string toString() const;
702
703
    /// Encode the OID to a byte buffer
704
    /// @return A byte buffer containing the encoded OID value
705
    std::vector<uint8_t> toBytes() const;
706
707
    friend std::ostream& operator<<(std::ostream& os, const Asn1ObjectIdentifier& oid)
708
0
    {
709
0
      return os << oid.toString();
710
0
    }
711
712
  protected:
713
472
    Asn1ObjectIdentifier() = default;
714
715
  private:
716
    std::vector<uint32_t> m_Components;
717
  };
718
719
  /// @class Asn1ObjectIdentifierRecord
720
  /// Represents an ASN.1 record with a value of type ObjectIdentifier
721
  class Asn1ObjectIdentifierRecord : public Asn1PrimitiveRecord
722
  {
723
    friend class Asn1Record;
724
725
  public:
726
    /// A constructor to create a ObjectIdentifier record
727
    /// @param[in] value The ObjectIdentifier (OID) to set as the record value
728
    explicit Asn1ObjectIdentifierRecord(const Asn1ObjectIdentifier& value);
729
730
    /// @return The OID value of this record
731
    const Asn1ObjectIdentifier& getValue()
732
0
    {
733
0
      decodeValueIfNeeded();
734
0
      return m_Value;
735
0
    }
736
737
  protected:
738
    void decodeValue(uint8_t* data, bool lazy) override;
739
    std::vector<uint8_t> encodeValue() const override;
740
741
    std::vector<std::string> toStringList() override;
742
743
  private:
744
    Asn1ObjectIdentifier m_Value;
745
746
472
    Asn1ObjectIdentifierRecord() = default;
747
  };
748
749
  /// @class Asn1TimeRecord
750
  /// An abstract class for representing ASN.1 time records (UTCTime and GeneralizedTime).
751
  /// This class is not instantiable, users should use either Asn1UtcTimeRecord or Asn1GeneralizedTimeRecord
752
  class Asn1TimeRecord : public Asn1PrimitiveRecord
753
  {
754
  public:
755
    /// @param[in] timezone A timezone string - should be in the format of "Z" for UTC or +=HHMM for other
756
    /// timezones. The default value is UTC
757
    /// @return The time-point value of this record
758
    /// @throws std::invalid_argument if timezone is not in the correct format
759
    std::chrono::system_clock::time_point getValue(const std::string& timezone = "Z")
760
0
    {
761
0
      decodeValueIfNeeded();
762
0
      return adjustTimezones(m_Value, "Z", timezone);
763
0
    };
764
765
    /// @param[in] format Requested value format
766
    /// @param[in] timezone A timezone string - should be in the format of "Z" for UTC or +=HHMM for other
767
    /// timezones. The default value is UTC
768
    /// @param[in] includeMilliseconds Should Include milliseconds in the returned string
769
    /// @return The value as string
770
    /// @throws std::invalid_argument if timezone is not in the correct format
771
    std::string getValueAsString(const std::string& format = "%Y-%m-%d %H:%M:%S", const std::string& timezone = "Z",
772
                                 bool includeMilliseconds = false);
773
774
  protected:
775
31
    Asn1TimeRecord() = default;
776
    explicit Asn1TimeRecord(Asn1UniversalTagType tagType, const std::chrono::system_clock::time_point& value,
777
                            const std::string& timezone);
778
779
    std::chrono::system_clock::time_point m_Value;
780
781
    std::vector<std::string> toStringList() override;
782
783
    static void validateTimezone(const std::string& timezone);
784
    static std::chrono::system_clock::time_point adjustTimezones(const std::chrono::system_clock::time_point& value,
785
                                                                 const std::string& fromTimezone,
786
                                                                 const std::string& toTimezone);
787
  };
788
789
  /// @class Asn1UtcTimeRecord
790
  /// Represents an ASN.1 record with a value of type UTCTime
791
  class Asn1UtcTimeRecord : public Asn1TimeRecord
792
  {
793
    friend class Asn1Record;
794
795
  public:
796
    /// A constructor to create a record of type UTC time
797
    /// @param[in] value A time-point to set as the record value
798
    /// @param[in] withSeconds Should write the ASN.1 record with second precision. The default is true
799
    explicit Asn1UtcTimeRecord(const std::chrono::system_clock::time_point& value, bool withSeconds = true);
800
801
  protected:
802
    void decodeValue(uint8_t* data, bool lazy) override;
803
    std::vector<uint8_t> encodeValue() const override;
804
805
  private:
806
21
    Asn1UtcTimeRecord() = default;
807
    bool m_WithSeconds = true;
808
  };
809
810
  /// @class Asn1GeneralizedTimeRecord
811
  /// Represents an ASN.1 record with a value of type GeneralizedTime
812
  class Asn1GeneralizedTimeRecord : public Asn1TimeRecord
813
  {
814
    friend class Asn1Record;
815
816
  public:
817
    /// A constructor to create a record of type generalized time
818
    /// @param[in] value A time-point to set as the record value
819
    /// @param[in] timezone The time-point's timezone - should be in the format of "Z" for UTC or +=HHMM for other
820
    /// timezones. If not provided it's assumed the timezone is UTC
821
    /// @throws std::invalid_argument if timezone is not in the correct format
822
    explicit Asn1GeneralizedTimeRecord(const std::chrono::system_clock::time_point& value,
823
                                       const std::string& timezone = "Z");
824
825
  protected:
826
    void decodeValue(uint8_t* data, bool lazy) override;
827
    std::vector<uint8_t> encodeValue() const override;
828
829
  private:
830
10
    Asn1GeneralizedTimeRecord() = default;
831
    std::string m_Timezone;
832
  };
833
834
  /// @class Asn1BitStringRecord
835
  /// Represents an ASN.1 record with a value of type BitString
836
  class Asn1BitStringRecord : public Asn1PrimitiveRecord
837
  {
838
    friend class Asn1Record;
839
840
  public:
841
    /// A constructor to create a record of type BitString
842
    /// @param value A bit string to set as the record value
843
    /// @throw std::invalid_argument if the string is not a valid bit string
844
    explicit Asn1BitStringRecord(const std::string& value);
845
846
    /// @return The bit string value of this record
847
    std::string getValue()
848
0
    {
849
0
      decodeValueIfNeeded();
850
0
      return m_Value.toString();
851
0
    };
852
853
  protected:
854
    void decodeValue(uint8_t* data, bool lazy) override;
855
    std::vector<uint8_t> encodeValue() const override;
856
857
    std::vector<std::string> toStringList() override;
858
859
  private:
860
    class BitSet
861
    {
862
    public:
863
133
      BitSet() = default;
864
      explicit BitSet(const std::string& value);
865
      BitSet(const uint8_t* data, size_t numBits);
866
867
      BitSet& operator=(const std::string& value);
868
869
      size_t sizeInBytes() const;
870
      std::string toString() const;
871
      std::vector<uint8_t> toBytes() const;
872
      size_t getNumBits() const
873
0
      {
874
0
        return m_NumBits;
875
0
      }
876
877
    private:
878
      void initFromString(const std::string& value);
879
880
      std::vector<std::bitset<8>> m_Data;
881
      size_t m_NumBits = 0;
882
    };
883
884
133
    Asn1BitStringRecord() = default;
885
886
    BitSet m_Value;
887
  };
888
}  // namespace pcpp