diff options
-rw-r--r-- | src/lib/asn1/asn1_time.cpp | 21 | ||||
-rw-r--r-- | src/lib/asn1/asn1_time.h | 2 | ||||
-rw-r--r-- | src/tests/data/asn1_time.vec | 37 | ||||
-rw-r--r-- | src/tests/test_asn1.cpp | 45 |
4 files changed, 100 insertions, 5 deletions
diff --git a/src/lib/asn1/asn1_time.cpp b/src/lib/asn1/asn1_time.cpp index e64fd57c7..863a064f0 100644 --- a/src/lib/asn1/asn1_time.cpp +++ b/src/lib/asn1/asn1_time.cpp @@ -213,7 +213,7 @@ void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag) } if(!passes_sanity_check()) - throw Invalid_Argument("Time did not pass sanity check: " + t_spec); + throw Invalid_Argument("Time " + t_spec + " does not seem to be valid"); } /* @@ -221,13 +221,26 @@ void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag) */ bool X509_Time::passes_sanity_check() const { - if(m_year < 1950 || m_year > 2100) + if(m_year < 1950 || m_year > 2200) return false; if(m_month == 0 || m_month > 12) return false; - if(m_day == 0 || m_day > 31) + + 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_hour >= 24 || m_minute > 60 || m_second > 60) + + 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) diff --git a/src/lib/asn1/asn1_time.h b/src/lib/asn1/asn1_time.h index 73bf2747f..717c58a7d 100644 --- a/src/lib/asn1/asn1_time.h +++ b/src/lib/asn1/asn1_time.h @@ -72,6 +72,8 @@ bool BOTAN_PUBLIC_API(2,0) operator>=(const X509_Time&, const X509_Time&); bool BOTAN_PUBLIC_API(2,0) operator<(const X509_Time&, const X509_Time&); bool BOTAN_PUBLIC_API(2,0) operator>(const X509_Time&, const X509_Time&); +typedef X509_Time ASN1_Time; + } #endif diff --git a/src/tests/data/asn1_time.vec b/src/tests/data/asn1_time.vec new file mode 100644 index 000000000..b1b33f279 --- /dev/null +++ b/src/tests/data/asn1_time.vec @@ -0,0 +1,37 @@ + +[UTC] + +Tspec = 500131053030Z + +[UTC.invalid] + +Tspec = 201801310590Z + +[Generalized] + +Tspec = 19500101000000Z +Tspec = 19500131053030Z +Tspec = 20000229000000Z +Tspec = 20180131000000Z +Tspec = 20180131053030Z +Tspec = 20200229000000Z +Tspec = 20201231235960Z +Tspec = 21000101000060Z +Tspec = 21000101005900Z +Tspec = 21000101230000Z +Tspec = 22001231235960Z + +[Generalized.invalid] + +Tspec = 20000001000000Z +Tspec = 20000100000000Z + +Tspec = 19490131053030Z +Tspec = 20180132000000Z +Tspec = 20180229000000Z +Tspec = 21000101000061Z +Tspec = 21000101006000Z +Tspec = 21000101240000Z +Tspec = 21000101990000Z +Tspec = 21000229000000Z +Tspec = 22010131053030Z diff --git a/src/tests/test_asn1.cpp b/src/tests/test_asn1.cpp index ae9c1dafb..f3bf3abc1 100644 --- a/src/tests/test_asn1.cpp +++ b/src/tests/test_asn1.cpp @@ -11,8 +11,8 @@ #include <botan/ber_dec.h> #include <botan/asn1_str.h> #include <botan/asn1_print.h> + #include <botan/asn1_time.h> #endif -#include <fstream> namespace Botan_Tests { @@ -291,6 +291,49 @@ class ASN1_Tests final : public Test BOTAN_REGISTER_TEST("asn1", ASN1_Tests); +class ASN1_Time_Parsing_Tests final : public Text_Based_Test + { + public: + ASN1_Time_Parsing_Tests() : + Text_Based_Test("asn1_time.vec", "Tspec") {} + + Test::Result run_one_test(const std::string& tag_str, const VarMap& vars) + { + Test::Result result("ASN.1 date parsing"); + + const std::string tspec = get_req_str(vars, "Tspec"); + + if(tag_str != "UTC" && + tag_str != "UTC.invalid" && + tag_str != "Generalized" && + tag_str != "Generalized.invalid") + { + throw Test_Error("Invalid tag value in ASN1 date parsing test"); + } + + const Botan::ASN1_Tag tag = + (tag_str == "UTC" || tag_str == "UTC.invalid") ? Botan::UTC_TIME : Botan::GENERALIZED_TIME; + + const bool valid = tag_str.find(".invalid") == std::string::npos; + + if(valid) + { + Botan::ASN1_Time time(tspec, tag); + result.test_success("Accepted valid time"); + } + else + { + result.test_throws("Invalid time rejected", [=]() { + Botan::ASN1_Time time(tspec, tag); + }); + } + + return result; + } + }; + +BOTAN_REGISTER_TEST("asn1_time", ASN1_Time_Parsing_Tests); + class ASN1_Printer_Tests final : public Test { public: |