aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/lib/asn1/asn1_time.cpp21
-rw-r--r--src/lib/asn1/asn1_time.h2
-rw-r--r--src/tests/data/asn1_time.vec37
-rw-r--r--src/tests/test_asn1.cpp45
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: