Skip to content

Commit d66f0d4

Browse files
authored
Add decoding and encoding of UTCTime and GeneralizedTime ASN.1 records (#1837)
1 parent 644e4ff commit d66f0d4

File tree

5 files changed

+643
-2
lines changed

5 files changed

+643
-2
lines changed

Common++/header/SystemUtils.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <cstdint>
66
#include <string>
77
#include <vector>
8+
#include <ctime>
89

910
/// @file
1011

@@ -161,6 +162,12 @@ namespace pcpp
161162
/// @return 0 for success, or -1 for failure
162163
int clockGetTime(long& sec, long& nsec);
163164

165+
/// Convert std::tm to time_t in UTC time, ignoring local timezone
166+
/// @param[in] tm The time to convert
167+
/// @return A time_t object representing the input time
168+
/// @throws std::runtime_error if a conversion error occurs
169+
time_t mkUtcTime(std::tm& tm);
170+
164171
/// A multi-platform version of the popular sleep method. This method simply runs the right sleep method, according
165172
/// to the platform it is running on.
166173
/// @param[in] seconds Number of seconds to sleep

Common++/src/SystemUtils.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,6 @@ namespace pcpp
258258

259259
#else // Linux
260260

261-
# include <ctime>
262-
263261
timespec tspec{};
264262
const int res = clock_gettime(CLOCK_REALTIME, &tspec);
265263
if (res == 0)
@@ -272,6 +270,15 @@ namespace pcpp
272270
#endif
273271
}
274272

273+
time_t mkUtcTime(std::tm& tm)
274+
{
275+
#if defined(_WIN32)
276+
return _mkgmtime(&tm);
277+
#else
278+
return timegm(&tm);
279+
#endif
280+
}
281+
275282
void multiPlatformSleep(uint32_t seconds)
276283
{
277284
std::this_thread::sleep_for(std::chrono::seconds(seconds));

Packet++/header/Asn1Codec.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <typeinfo>
66
#include <stdexcept>
77
#include <sstream>
8+
#include <chrono>
89
#include "PointerVector.h"
910

1011
/// @file
@@ -661,4 +662,89 @@ namespace pcpp
661662

662663
Asn1ObjectIdentifierRecord() = default;
663664
};
665+
666+
/// @class Asn1TimeRecord
667+
/// An abstract class for representing ASN.1 time records (UTCTime and GeneralizedTime).
668+
/// This class is not instantiable, users should use either Asn1UtcTimeRecord or Asn1GeneralizedTimeRecord
669+
class Asn1TimeRecord : public Asn1PrimitiveRecord
670+
{
671+
public:
672+
/// @param[in] timezone A timezone string - should be in the format of "Z" for UTC or +=HHMM for other
673+
/// timezones. The default value is UTC
674+
/// @return The time-point value of this record
675+
/// @throws std::invalid_argument if timezone is not in the correct format
676+
std::chrono::system_clock::time_point getValue(const std::string& timezone = "Z")
677+
{
678+
decodeValueIfNeeded();
679+
return adjustTimezones(m_Value, "Z", timezone);
680+
};
681+
682+
/// @param[in] format Requested value format
683+
/// @param[in] timezone A timezone string - should be in the format of "Z" for UTC or +=HHMM for other
684+
/// timezones. The default value is UTC
685+
/// @param[in] includeMilliseconds Should Include milliseconds in the returned string
686+
/// @return The value as string
687+
/// @throws std::invalid_argument if timezone is not in the correct format
688+
std::string getValueAsString(const std::string& format = "%Y-%m-%d %H:%M:%S", const std::string& timezone = "Z",
689+
bool includeMilliseconds = false);
690+
691+
protected:
692+
Asn1TimeRecord() = default;
693+
explicit Asn1TimeRecord(Asn1UniversalTagType tagType, const std::chrono::system_clock::time_point& value,
694+
const std::string& timezone);
695+
696+
std::chrono::system_clock::time_point m_Value;
697+
698+
std::vector<std::string> toStringList() override;
699+
700+
static void validateTimezone(const std::string& timezone);
701+
static std::chrono::system_clock::time_point adjustTimezones(const std::chrono::system_clock::time_point& value,
702+
const std::string& fromTimezone,
703+
const std::string& toTimezone);
704+
};
705+
706+
/// @class Asn1UtcTimeRecord
707+
/// Represents an ASN.1 record with a value of type UTCTime
708+
class Asn1UtcTimeRecord : public Asn1TimeRecord
709+
{
710+
friend class Asn1Record;
711+
712+
public:
713+
/// A constructor to create a record of type UTC time
714+
/// @param[in] value A time-point to set as the record value
715+
/// @param[in] withSeconds Should write the ASN.1 record with second precision. The default is true
716+
explicit Asn1UtcTimeRecord(const std::chrono::system_clock::time_point& value, bool withSeconds = true);
717+
718+
protected:
719+
void decodeValue(uint8_t* data, bool lazy) override;
720+
std::vector<uint8_t> encodeValue() const override;
721+
722+
private:
723+
Asn1UtcTimeRecord() = default;
724+
bool m_WithSeconds = true;
725+
};
726+
727+
/// @class Asn1GeneralizedTimeRecord
728+
/// Represents an ASN.1 record with a value of type GeneralizedTime
729+
class Asn1GeneralizedTimeRecord : public Asn1TimeRecord
730+
{
731+
friend class Asn1Record;
732+
733+
public:
734+
/// A constructor to create a record of type generalized time
735+
/// @param[in] value A time-point to set as the record value
736+
/// @param[in] timezone The time-point's timezone - should be in the format of "Z" for UTC or +=HHMM for other
737+
/// timezones. If not provided it's assumed the timezone is UTC
738+
/// @throws std::invalid_argument if timezone is not in the correct format
739+
explicit Asn1GeneralizedTimeRecord(const std::chrono::system_clock::time_point& value,
740+
const std::string& timezone = "Z");
741+
742+
protected:
743+
void decodeValue(uint8_t* data, bool lazy) override;
744+
std::vector<uint8_t> encodeValue() const override;
745+
746+
private:
747+
Asn1GeneralizedTimeRecord() = default;
748+
std::string m_Timezone;
749+
};
664750
} // namespace pcpp

0 commit comments

Comments
 (0)