aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/botan/src/lib/asn1/asn1_time.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/3rdparty/botan/src/lib/asn1/asn1_time.cpp')
-rw-r--r--src/libs/3rdparty/botan/src/lib/asn1/asn1_time.cpp283
1 files changed, 283 insertions, 0 deletions
diff --git a/src/libs/3rdparty/botan/src/lib/asn1/asn1_time.cpp b/src/libs/3rdparty/botan/src/lib/asn1/asn1_time.cpp
new file mode 100644
index 0000000000..43f94af6aa
--- /dev/null
+++ b/src/libs/3rdparty/botan/src/lib/asn1/asn1_time.cpp
@@ -0,0 +1,283 @@
+/*
+* X.509 Time Types
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/asn1_time.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/exceptn.h>
+#include <botan/parsing.h>
+#include <botan/calendar.h>
+#include <sstream>
+#include <iomanip>
+
+namespace Botan {
+
+X509_Time::X509_Time(const std::chrono::system_clock::time_point& time)
+ {
+ calendar_point cal = calendar_value(time);
+
+ m_year = cal.get_year();
+ m_month = cal.get_month();
+ m_day = cal.get_day();
+ m_hour = cal.get_hour();
+ m_minute = cal.get_minutes();
+ m_second = cal.get_seconds();
+
+ m_tag = (m_year >= 2050) ? GENERALIZED_TIME : UTC_TIME;
+ }
+
+X509_Time::X509_Time(const std::string& t_spec, ASN1_Tag tag)
+ {
+ set_to(t_spec, tag);
+ }
+
+void X509_Time::encode_into(DER_Encoder& der) const
+ {
+ BOTAN_ARG_CHECK(m_tag == UTC_TIME || m_tag == GENERALIZED_TIME,
+ "X509_Time: Bad encoding tag");
+
+ der.add_object(m_tag, UNIVERSAL, to_string());
+ }
+
+void X509_Time::decode_from(BER_Decoder& source)
+ {
+ BER_Object ber_time = source.get_next_object();
+
+ set_to(ASN1::to_string(ber_time), ber_time.type());
+ }
+
+std::string X509_Time::to_string() const
+ {
+ if(time_is_set() == false)
+ throw Invalid_State("X509_Time::as_string: No time set");
+
+ uint32_t full_year = m_year;
+
+ if(m_tag == UTC_TIME)
+ {
+ if(m_year < 1950 || m_year >= 2050)
+ throw Encoding_Error("X509_Time: The time " + readable_string() +
+ " cannot be encoded as a UTCTime");
+
+ full_year = (m_year >= 2000) ? (m_year - 2000) : (m_year - 1900);
+ }
+
+ const uint64_t YEAR_FACTOR = 10000000000ULL;
+ const uint64_t MON_FACTOR = 100000000;
+ const uint64_t DAY_FACTOR = 1000000;
+ const uint64_t HOUR_FACTOR = 10000;
+ const uint64_t MIN_FACTOR = 100;
+
+ const uint64_t int_repr =
+ YEAR_FACTOR * full_year +
+ MON_FACTOR * m_month +
+ DAY_FACTOR * m_day +
+ HOUR_FACTOR * m_hour +
+ MIN_FACTOR * m_minute +
+ m_second;
+
+ std::string repr = std::to_string(int_repr) + "Z";
+
+ uint32_t desired_size = (m_tag == UTC_TIME) ? 13 : 15;
+
+ while(repr.size() < desired_size)
+ repr = "0" + repr;
+
+ return repr;
+ }
+
+std::string X509_Time::readable_string() const
+ {
+ if(time_is_set() == false)
+ throw Invalid_State("X509_Time::readable_string: No time set");
+
+ // desired format: "%04d/%02d/%02d %02d:%02d:%02d UTC"
+ std::stringstream output;
+ output << std::setfill('0')
+ << std::setw(4) << m_year << "/"
+ << std::setw(2) << m_month << "/"
+ << std::setw(2) << m_day
+ << " "
+ << std::setw(2) << m_hour << ":"
+ << std::setw(2) << m_minute << ":"
+ << std::setw(2) << m_second
+ << " UTC";
+
+ return output.str();
+ }
+
+bool X509_Time::time_is_set() const
+ {
+ return (m_year != 0);
+ }
+
+int32_t X509_Time::cmp(const X509_Time& other) const
+ {
+ if(time_is_set() == false)
+ throw Invalid_State("X509_Time::cmp: No time set");
+
+ const int32_t EARLIER = -1, LATER = 1, SAME_TIME = 0;
+
+ if(m_year < other.m_year) return EARLIER;
+ if(m_year > other.m_year) return LATER;
+ if(m_month < other.m_month) return EARLIER;
+ if(m_month > other.m_month) return LATER;
+ if(m_day < other.m_day) return EARLIER;
+ if(m_day > other.m_day) return LATER;
+ if(m_hour < other.m_hour) return EARLIER;
+ if(m_hour > other.m_hour) return LATER;
+ if(m_minute < other.m_minute) return EARLIER;
+ if(m_minute > other.m_minute) return LATER;
+ if(m_second < other.m_second) return EARLIER;
+ if(m_second > other.m_second) return LATER;
+
+ return SAME_TIME;
+ }
+
+void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
+ {
+ if(spec_tag == UTC_OR_GENERALIZED_TIME)
+ {
+ try
+ {
+ set_to(t_spec, GENERALIZED_TIME);
+ return;
+ }
+ catch(Invalid_Argument&) {} // Not a generalized time. Continue
+
+ try
+ {
+ set_to(t_spec, UTC_TIME);
+ return;
+ }
+ catch(Invalid_Argument&) {} // Not a UTC time. Continue
+
+ throw Invalid_Argument("Time string could not be parsed as GeneralizedTime or UTCTime.");
+ }
+
+ BOTAN_ASSERT(spec_tag == UTC_TIME || spec_tag == GENERALIZED_TIME, "Invalid tag.");
+
+ BOTAN_ARG_CHECK(t_spec.size() > 0, "Time string must not be empty.");
+
+ BOTAN_ARG_CHECK(t_spec.back() == 'Z', "Botan does not support times with timezones other than Z");
+
+ if(spec_tag == GENERALIZED_TIME)
+ {
+ BOTAN_ARG_CHECK(t_spec.size() == 15, "Invalid GeneralizedTime string");
+ }
+ else if(spec_tag == UTC_TIME)
+ {
+ BOTAN_ARG_CHECK(t_spec.size() == 13, "Invalid UTCTime string");
+ }
+
+ const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4;
+
+ std::vector<std::string> params;
+ std::string current;
+
+ for(size_t j = 0; j != YEAR_SIZE; ++j)
+ current += t_spec[j];
+ params.push_back(current);
+ current.clear();
+
+ for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j)
+ {
+ current += t_spec[j];
+ if(current.size() == 2)
+ {
+ params.push_back(current);
+ current.clear();
+ }
+ }
+
+ m_year = to_u32bit(params[0]);
+ m_month = to_u32bit(params[1]);
+ m_day = to_u32bit(params[2]);
+ m_hour = to_u32bit(params[3]);
+ m_minute = to_u32bit(params[4]);
+ m_second = (params.size() == 6) ? to_u32bit(params[5]) : 0;
+ m_tag = spec_tag;
+
+ if(spec_tag == UTC_TIME)
+ {
+ if(m_year >= 50) m_year += 1900;
+ else m_year += 2000;
+ }
+
+ if(!passes_sanity_check())
+ throw Invalid_Argument("Time " + t_spec + " does not seem to be valid");
+ }
+
+/*
+* Do a general sanity check on the time
+*/
+bool X509_Time::passes_sanity_check() const
+ {
+ if(m_year < 1950 || m_year > 2200)
+ return false;
+ if(m_month == 0 || m_month > 12)
+ return false;
+
+ const uint32_t days_in_month[12] = { 31, 28+1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+ if(m_day == 0 || m_day > days_in_month[m_month-1])
+ return false;
+
+ if(m_month == 2 && m_day == 29)
+ {
+ if(m_year % 4 != 0)
+ return false; // not a leap year
+
+ if(m_year % 100 == 0 && m_year % 400 != 0)
+ return false;
+ }
+
+ if(m_hour >= 24 || m_minute >= 60 || m_second > 60)
+ return false;
+
+ if (m_tag == UTC_TIME)
+ {
+ /*
+ UTCTime limits the value of components such that leap seconds
+ are not covered. See "UNIVERSAL 23" in "Information technology
+ Abstract Syntax Notation One (ASN.1): Specification of basic notation"
+
+ http://www.itu.int/ITU-T/studygroups/com17/languages/
+ */
+ if (m_hour > 23 || m_minute > 59 || m_second > 59)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+std::chrono::system_clock::time_point X509_Time::to_std_timepoint() const
+ {
+ return calendar_point(m_year, m_month, m_day, m_hour, m_minute, m_second).to_std_timepoint();
+ }
+
+/*
+* Compare two X509_Times for in various ways
+*/
+bool operator==(const X509_Time& t1, const X509_Time& t2)
+ { return (t1.cmp(t2) == 0); }
+bool operator!=(const X509_Time& t1, const X509_Time& t2)
+ { return (t1.cmp(t2) != 0); }
+
+bool operator<=(const X509_Time& t1, const X509_Time& t2)
+ { return (t1.cmp(t2) <= 0); }
+bool operator>=(const X509_Time& t1, const X509_Time& t2)
+ { return (t1.cmp(t2) >= 0); }
+
+bool operator<(const X509_Time& t1, const X509_Time& t2)
+ { return (t1.cmp(t2) < 0); }
+bool operator>(const X509_Time& t1, const X509_Time& t2)
+ { return (t1.cmp(t2) > 0); }
+
+}