8#include <botan/asn1_time.h>
10#include <botan/assert.h>
11#include <botan/ber_dec.h>
12#include <botan/der_enc.h>
13#include <botan/exceptn.h>
14#include <botan/internal/calendar.h>
15#include <botan/internal/fmt.h>
16#include <botan/internal/parsing.h>
24std::string zero_pad(uint32_t value,
size_t digits) {
25 std::string s = std::to_string(value);
27 const size_t padding = digits - s.size();
31 return std::string(padding,
'0') + s;
42 uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second,
ASN1_Type tag) :
43 m_year(year), m_month(month), m_day(day), m_hour(hour), m_minute(minute), m_second(second), m_tag(tag) {
54 const uint16_t min_year = 1950;
57 if(m_year < min_year || m_year > max_year) {
58 throw Invalid_Argument(
fmt(
"ASN1_Time year {} is out of range ({} to {})", m_year, min_year, max_year));
61 if(m_month < 1 || m_month > 12) {
62 throw Invalid_Argument(
fmt(
"ASN1_Time month {} is out of range",
static_cast<uint32_t
>(m_month)));
65 constexpr uint8_t days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
67 const bool is_leap_year = (m_year % 4 == 0) && (m_year % 100 != 0 || m_year % 400 == 0);
68 const uint8_t max_day = (m_month == 2 && is_leap_year) ? 29 : days_in_month[m_month - 1];
70 if(m_day < 1 || m_day > max_day) {
71 throw Invalid_Argument(
fmt(
"ASN1_Time day {} is out of range for month {}",
72 static_cast<uint32_t
>(m_day),
73 static_cast<uint32_t
>(m_month)));
77 throw Invalid_Argument(
fmt(
"ASN1_Time hour {} is out of range",
static_cast<uint32_t
>(m_hour)));
81 throw Invalid_Argument(
fmt(
"ASN1_Time minute {} is out of range",
static_cast<uint32_t
>(m_minute)));
89 throw Invalid_Argument(
fmt(
"ASN1_Time second {} is out of range",
static_cast<uint32_t
>(m_second)));
100 static_cast<uint8_t
>(cal.
month()),
101 static_cast<uint8_t
>(cal.
day()),
102 static_cast<uint8_t
>(cal.
hour()),
103 static_cast<uint8_t
>(cal.
minutes()),
104 static_cast<uint8_t
>(cal.
seconds()),
113 BOTAN_ARG_CHECK(t_spec.size() == 15,
"Invalid GeneralizedTime input string");
118 BOTAN_ARG_CHECK(t_spec.back() ==
'Z',
"Botan does not support ASN1 times with timezones other than Z");
120 const size_t field_len = 2;
123 const size_t year_start = 0;
124 const size_t month_start = year_start + year_len;
125 const size_t day_start = month_start + field_len;
126 const size_t hour_start = day_start + field_len;
127 const size_t min_start = hour_start + field_len;
128 const size_t sec_start = min_start + field_len;
130 uint32_t year =
to_u32bit(t_spec.substr(year_start, year_len));
131 const uint32_t month =
to_u32bit(t_spec.substr(month_start, field_len));
132 const uint32_t day =
to_u32bit(t_spec.substr(day_start, field_len));
133 const uint32_t hour =
to_u32bit(t_spec.substr(hour_start, field_len));
134 const uint32_t minute =
to_u32bit(t_spec.substr(min_start, field_len));
135 const uint32_t second =
to_u32bit(t_spec.substr(sec_start, field_len));
139 year += (year >= 50) ? 1900 : 2000;
142 return ASN1_Time(
static_cast<uint16_t
>(year),
143 static_cast<uint8_t
>(month),
144 static_cast<uint8_t
>(day),
145 static_cast<uint8_t
>(hour),
146 static_cast<uint8_t
>(minute),
147 static_cast<uint8_t
>(second),
153 if(t_spec.size() == 13) {
155 }
else if(t_spec.size() == 15) {
158 throw Invalid_Argument(
"Time string could not be parsed as GeneralizedTime or UTCTime.");
174 static_cast<uint32_t
>(ber_time.
type()),
175 static_cast<uint32_t
>(ber_time.
get_class())));
194 std::ostringstream out;
198 if(m_year < 1950 || m_year >= 2050) {
202 out << (zero_pad((m_year >= 2000) ? (m_year - 2000) : (m_year - 1900), 2));
204 out << zero_pad(m_year, 4);
208 out << zero_pad(m_month, 2)
209 << zero_pad(m_day, 2)
210 << zero_pad(m_hour, 2)
211 << zero_pad(m_minute, 2)
212 << zero_pad(m_second, 2) <<
"Z";
220 throw Invalid_State(
"ASN1_Time::readable_string: No time set");
225 std::ostringstream out;
227 out << zero_pad(m_year, 4) <<
"/" << zero_pad(m_month, 2) <<
"/" << zero_pad(m_day, 2) <<
" ";
228 out << zero_pad(m_hour, 2) <<
":" << zero_pad(m_minute, 2) <<
":" << zero_pad(m_second, 2) <<
" UTC";
234 return (m_year != 0);
239 throw Invalid_State(
"ASN1_Time::cmp: Cannot compare empty times");
242 constexpr int32_t EARLIER = -1;
243 constexpr int32_t LATER = 1;
244 constexpr int32_t SAME_TIME = 0;
246 if(m_year < other.m_year) {
249 if(m_year > other.m_year) {
252 if(m_month < other.m_month) {
255 if(m_month > other.m_month) {
258 if(m_day < other.m_day) {
261 if(m_day > other.m_day) {
264 if(m_hour < other.m_hour) {
267 if(m_hour > other.m_hour) {
270 if(m_minute < other.m_minute) {
273 if(m_minute > other.m_minute) {
276 if(m_second < other.m_second) {
279 if(m_second > other.m_second) {
294 return static_cast<uint64_t
>(tse);
296 throw Encoding_Error(
"ASN1_Time::time_since_epoch value is prior to epoch");
304 return (t1.
cmp(t2) == 0);
308 return (t1.
cmp(t2) != 0);
312 return (t1.
cmp(t2) <= 0);
316 return (t1.
cmp(t2) >= 0);
320 return (t1.
cmp(t2) < 0);
324 return (t1.
cmp(t2) > 0);
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
uint64_t time_since_epoch() const
Return time since epoch.
std::chrono::system_clock::time_point to_std_timepoint() const
Returns a STL timepoint object.
void decode_from(BER_Decoder &from) override
static ASN1_Time from_seconds_since_epoch(uint64_t seconds)
Create an ASN1_Time from seconds since epoch.
std::string to_string() const
Return an internal string representation of the time.
static ASN1_Time from_string(std::string_view t_spec)
ASN1_Time()=default
Create an invalid ASN1_Time.
static ASN1_Time from_time_point(const std::chrono::system_clock::time_point &time)
Create a ASN1_Time from a time point.
bool time_is_set() const
Return if the time has been set somehow.
int32_t cmp(const ASN1_Time &other) const
Compare this time against another.
void encode_into(DER_Encoder &to) const override
DER encode a ASN1_Time.
std::string readable_string() const
Returns a human friendly string representation of no particular formatting.
BER_Object get_next_object()
ASN1_Class get_class() const
DER_Encoder & add_object(ASN1_Type type_tag, ASN1_Class class_tag, const uint8_t rep[], size_t length)
const char * what() const noexcept override
int64_t seconds_since_epoch() const
std::chrono::system_clock::time_point to_std_timepoint() const
std::string to_string(const BER_Object &obj)
bool operator>(const ASN1_Time &t1, const ASN1_Time &t2)
std::string fmt(std::string_view format, const T &... args)
bool operator<(const OID &a, const OID &b)
bool operator>=(const ASN1_Time &t1, const ASN1_Time &t2)
bool operator<=(const ASN1_Time &t1, const ASN1_Time &t2)
bool operator!=(const AlgorithmIdentifier &x, const AlgorithmIdentifier &y)
bool operator==(const AlgorithmIdentifier &x, const AlgorithmIdentifier &y)
uint32_t to_u32bit(std::string_view input)