Coverage Report

Created: 2025-07-11 07:47

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