/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 |