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>
29 m_month = cal.
month();
44 if(t_spec.size() == 13) {
46 }
else if(t_spec.size() == 15) {
49 throw Invalid_Argument(
"Time string could not be parsed as GeneralizedTime or UTCTime.");
65 static_cast<uint32_t
>(ber_time.
type()),
66 static_cast<uint32_t
>(ber_time.
get_class())));
81 uint32_t full_year = m_year;
84 if(m_year < 1950 || m_year >= 2050) {
88 full_year = (m_year >= 2000) ? (m_year - 2000) : (m_year - 1900);
91 const uint64_t year_factor = 10000000000;
92 const uint64_t mon_factor = 100000000;
93 const uint64_t day_factor = 1000000;
94 const uint64_t hour_factor = 10000;
95 const uint64_t min_factor = 100;
97 const uint64_t int_repr = year_factor * full_year + mon_factor * m_month + day_factor * m_day +
98 hour_factor * m_hour + min_factor * m_minute + m_second;
100 const std::string repr = std::to_string(int_repr) +
"Z";
104 const std::string zero_padding(desired_size - repr.size(),
'0');
106 return zero_padding + repr;
111 throw Invalid_State(
"ASN1_Time::readable_string: No time set");
115 std::stringstream output;
116 output << std::setfill(
'0') << std::setw(4) << m_year <<
"/" << std::setw(2) << m_month <<
"/" << std::setw(2)
117 << m_day <<
" " << std::setw(2) << m_hour <<
":" << std::setw(2) << m_minute <<
":" << std::setw(2)
118 << m_second <<
" UTC";
124 return (m_year != 0);
129 throw Invalid_State(
"ASN1_Time::cmp: Cannot compare empty times");
132 constexpr int32_t EARLIER = -1;
133 constexpr int32_t LATER = 1;
134 constexpr int32_t SAME_TIME = 0;
136 if(m_year < other.m_year) {
139 if(m_year > other.m_year) {
142 if(m_month < other.m_month) {
145 if(m_month > other.m_month) {
148 if(m_day < other.m_day) {
151 if(m_day > other.m_day) {
154 if(m_hour < other.m_hour) {
157 if(m_hour > other.m_hour) {
160 if(m_minute < other.m_minute) {
163 if(m_minute > other.m_minute) {
166 if(m_second < other.m_second) {
169 if(m_second > other.m_second) {
176void ASN1_Time::set_to(std::string_view t_spec,
ASN1_Type spec_tag) {
178 "Invalid tag for ASN1_Time");
181 BOTAN_ARG_CHECK(t_spec.size() == 15,
"Invalid GeneralizedTime input string");
186 BOTAN_ARG_CHECK(t_spec.back() ==
'Z',
"Botan does not support ASN1 times with timezones other than Z");
188 const size_t field_len = 2;
190 const size_t year_start = 0;
192 const size_t month_start = year_start + year_len;
193 const size_t day_start = month_start + field_len;
194 const size_t hour_start = day_start + field_len;
195 const size_t min_start = hour_start + field_len;
196 const size_t sec_start = min_start + field_len;
198 m_year =
to_u32bit(t_spec.substr(year_start, year_len));
199 m_month =
to_u32bit(t_spec.substr(month_start, field_len));
200 m_day =
to_u32bit(t_spec.substr(day_start, field_len));
201 m_hour =
to_u32bit(t_spec.substr(hour_start, field_len));
202 m_minute =
to_u32bit(t_spec.substr(min_start, field_len));
203 m_second =
to_u32bit(t_spec.substr(sec_start, field_len));
214 if(!passes_sanity_check()) {
215 throw Invalid_Argument(
fmt(
"ASN1_Time string '{}' does not seem to be valid", t_spec));
222bool ASN1_Time::passes_sanity_check()
const {
224 if(m_year < 1950 || m_year > 3100) {
227 if(m_month == 0 || m_month > 12) {
231 const uint32_t days_in_month[12] = {31, 28 + 1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
233 if(m_day == 0 || m_day > days_in_month[m_month - 1]) {
237 if(m_month == 2 && m_day == 29) {
238 if(m_year % 4 != 0) {
242 if(m_year % 100 == 0 && m_year % 400 != 0) {
247 if(m_hour >= 24 || m_minute >= 60 || m_second > 60) {
279 return (t1.
cmp(t2) == 0);
283 return (t1.
cmp(t2) != 0);
287 return (t1.
cmp(t2) <= 0);
291 return (t1.
cmp(t2) >= 0);
295 return (t1.
cmp(t2) < 0);
299 return (t1.
cmp(t2) > 0);
#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.
ASN1_Time()=default
Create an invalid ASN1_Time.
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
uint64_t seconds_since_epoch() const
std::chrono::system_clock::time_point to_std_timepoint() const
std::string to_string(const BER_Object &obj)
uint32_t to_u32bit(std::string_view str_view)
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 AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
bool operator>=(const ASN1_Time &t1, const ASN1_Time &t2)
bool operator==(const AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
bool operator<=(const ASN1_Time &t1, const ASN1_Time &t2)