aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Warta <[email protected]>2015-08-09 17:13:29 +0200
committerSimon Warta <[email protected]>2015-08-11 10:50:14 +0200
commit1019b07e02a2ca68798dd9cadfe604dff9c0cc6b (patch)
treeeb555b683b4160742a5c3eefb4ef7ed500efbf4b /src
parent3b0ab51f41325a20ba0b8113418d9d916d8e2857 (diff)
Add stricter time parsing; Add more tests
Diffstat (limited to 'src')
-rw-r--r--src/lib/asn1/asn1_time.cpp31
-rw-r--r--src/lib/utils/exceptn.h11
-rw-r--r--src/tests/catchy/test_x509.cpp80
3 files changed, 113 insertions, 9 deletions
diff --git a/src/lib/asn1/asn1_time.cpp b/src/lib/asn1/asn1_time.cpp
index b61879b53..b7cf589a2 100644
--- a/src/lib/asn1/asn1_time.cpp
+++ b/src/lib/asn1/asn1_time.cpp
@@ -9,6 +9,7 @@
#include <botan/der_enc.h>
#include <botan/ber_dec.h>
#include <botan/charset.h>
+#include <botan/exceptn.h>
#include <botan/parsing.h>
#include <botan/calendar.h>
#include <sstream>
@@ -159,7 +160,16 @@ void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
throw Invalid_Argument("Time string could not be parsed as GeneralizedTime or UTCTime.");
}
- else if(spec_tag == GENERALIZED_TIME)
+
+ BOTAN_ASSERT(spec_tag == UTC_TIME || spec_tag == GENERALIZED_TIME, "Invalid tag.");
+
+ if(t_spec.empty())
+ throw Invalid_Argument("Time string must not be empty.");
+
+ if(t_spec.back() != 'Z')
+ throw Unsupported_Argument("Botan does not support times with timezones other than Z: " + t_spec);
+
+ if(spec_tag == GENERALIZED_TIME)
{
if(t_spec.size() != 13 && t_spec.size() != 15)
throw Invalid_Argument("Invalid GeneralizedTime string: '" + t_spec + "'");
@@ -169,13 +179,6 @@ void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
if(t_spec.size() != 11 && t_spec.size() != 13)
throw Invalid_Argument("Invalid UTCTime string: '" + t_spec + "'");
}
- else
- {
- throw Invalid_Argument("Invalid time tag " + std::to_string(spec_tag) + " val " + t_spec);
- }
-
- if(t_spec[t_spec.size()-1] != 'Z')
- throw Invalid_Argument("Invalid time encoding: " + t_spec);
const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4;
@@ -228,6 +231,18 @@ bool X509_Time::passes_sanity_check() const
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;
}
diff --git a/src/lib/utils/exceptn.h b/src/lib/utils/exceptn.h
index 23ac01cff..7e16a5dec 100644
--- a/src/lib/utils/exceptn.h
+++ b/src/lib/utils/exceptn.h
@@ -20,6 +20,17 @@ typedef std::runtime_error Exception;
typedef std::invalid_argument Invalid_Argument;
/**
+* Unsupported_Argument Exception
+*
+* An argument that is invalid because it is not supported by Botan.
+* It might or might not be valid in another context like a standard.
+*/
+struct BOTAN_DLL Unsupported_Argument : public Invalid_Argument
+ {
+ Unsupported_Argument(const std::string& msg) : Invalid_Argument(msg) {}
+ };
+
+/**
* Invalid_State Exception
*/
struct BOTAN_DLL Invalid_State : public Exception
diff --git a/src/tests/catchy/test_x509.cpp b/src/tests/catchy/test_x509.cpp
index 448e06847..cb2f8f0cf 100644
--- a/src/tests/catchy/test_x509.cpp
+++ b/src/tests/catchy/test_x509.cpp
@@ -5,6 +5,7 @@
#if defined(BOTAN_HAS_ASN1)
+#include <botan/exceptn.h>
#include <botan/asn1_time.h>
using namespace Botan;
@@ -47,8 +48,52 @@ TEST_CASE("no time", "[X509]")
CHECK_THAT(time.time_is_set(), Equals(false));
}
-TEST_CASE("invalid time", "[X509]")
+TEST_CASE("valid UTCTime", "[X509]")
{
+ SECTION("precision: minute; including timezone: no", "Length 11")
+ {
+ CHECK_NOTHROW(X509_Time("0802010000Z", ASN1_Tag::UTC_TIME));
+ CHECK_NOTHROW(X509_Time("0802011724Z", ASN1_Tag::UTC_TIME));
+ CHECK_NOTHROW(X509_Time("0406142334Z", ASN1_Tag::UTC_TIME));
+ CHECK_NOTHROW(X509_Time("9906142334Z", ASN1_Tag::UTC_TIME));
+ CHECK_NOTHROW(X509_Time("0006142334Z", ASN1_Tag::UTC_TIME));
+ }
+
+ SECTION("precision: seconds; including timezone: no", "Length 13")
+ {
+ CHECK_NOTHROW(X509_Time("080201000000Z", ASN1_Tag::UTC_TIME));
+ CHECK_NOTHROW(X509_Time("080201172412Z", ASN1_Tag::UTC_TIME));
+ CHECK_NOTHROW(X509_Time("040614233433Z", ASN1_Tag::UTC_TIME));
+ CHECK_NOTHROW(X509_Time("990614233444Z", ASN1_Tag::UTC_TIME));
+ CHECK_NOTHROW(X509_Time("000614233455Z", ASN1_Tag::UTC_TIME));
+ }
+
+ SECTION("precision: minute; including timezone: yes", "Length 15")
+ {
+ // Valid times that are not supported by Botan
+ CHECK_THROWS_AS(X509_Time("0802010000-0000", ASN1_Tag::UTC_TIME), Unsupported_Argument);
+ CHECK_THROWS_AS(X509_Time("0802011724+0000", ASN1_Tag::UTC_TIME), Unsupported_Argument);
+ CHECK_THROWS_AS(X509_Time("0406142334-0500", ASN1_Tag::UTC_TIME), Unsupported_Argument);
+ CHECK_THROWS_AS(X509_Time("9906142334+0500", ASN1_Tag::UTC_TIME), Unsupported_Argument);
+ CHECK_THROWS_AS(X509_Time("0006142334-0530", ASN1_Tag::UTC_TIME), Unsupported_Argument);
+ CHECK_THROWS_AS(X509_Time("0006142334+0530", ASN1_Tag::UTC_TIME), Unsupported_Argument);
+ }
+
+ SECTION("precision: seconds; including timezone: yes", "Length 17")
+ {
+ // Valid times that are not supported by Botan
+ CHECK_THROWS_AS(X509_Time("080201000000-0000", ASN1_Tag::UTC_TIME), Unsupported_Argument);
+ CHECK_THROWS_AS(X509_Time("080201172412+0000", ASN1_Tag::UTC_TIME), Unsupported_Argument);
+ CHECK_THROWS_AS(X509_Time("040614233433-0500", ASN1_Tag::UTC_TIME), Unsupported_Argument);
+ CHECK_THROWS_AS(X509_Time("990614233444+0500", ASN1_Tag::UTC_TIME), Unsupported_Argument);
+ CHECK_THROWS_AS(X509_Time("000614233455-0530", ASN1_Tag::UTC_TIME), Unsupported_Argument);
+ CHECK_THROWS_AS(X509_Time("000614233455+0530", ASN1_Tag::UTC_TIME), Unsupported_Argument);
+ }
+ }
+
+TEST_CASE("invalid UTCTime", "[X509]")
+ {
+ // invalid length
CHECK_THROWS(X509_Time("", ASN1_Tag::UTC_TIME));
CHECK_THROWS(X509_Time(" ", ASN1_Tag::UTC_TIME));
CHECK_THROWS(X509_Time("2008`02-01", ASN1_Tag::UTC_TIME));
@@ -56,6 +101,39 @@ TEST_CASE("invalid time", "[X509]")
CHECK_THROWS(X509_Time("2000-02-01 17", ASN1_Tag::UTC_TIME));
CHECK_THROWS(X509_Time("999921", ASN1_Tag::UTC_TIME));
+ // valid length 13 -> range check
+ CHECK_THROWS(X509_Time("080201000061Z", ASN1_Tag::UTC_TIME)); // seconds too big (61)
+ CHECK_THROWS(X509_Time("080201000060Z", ASN1_Tag::UTC_TIME)); // seconds too big (60, leap seconds not covered by the standard)
+ CHECK_THROWS(X509_Time("0802010000-1Z", ASN1_Tag::UTC_TIME)); // seconds too small (-1)
+ CHECK_THROWS(X509_Time("080201006000Z", ASN1_Tag::UTC_TIME)); // minutes too big (60)
+ CHECK_THROWS(X509_Time("080201240000Z", ASN1_Tag::UTC_TIME)); // hours too big (24:00)
+
+ // valid length 13 -> invalid numbers
+ CHECK_THROWS(X509_Time("08020123112 Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("08020123112!Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("08020123112,Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("08020123112\nZ", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("080201232 33Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("080201232!33Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("080201232,33Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("080201232\n33Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("0802012 3344Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("0802012!3344Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("0802012,3344Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("08022\n334455Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("08022 334455Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("08022!334455Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("08022,334455Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("08022\n334455Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("082 33445511Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("082!33445511Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("082,33445511Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("082\n33445511Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("2 2211221122Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("2!2211221122Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("2,2211221122Z", ASN1_Tag::UTC_TIME));
+ CHECK_THROWS(X509_Time("2\n2211221122Z", ASN1_Tag::UTC_TIME));
+
// wrong time zone
CHECK_THROWS(X509_Time("0802010000", ASN1_Tag::UTC_TIME));
CHECK_THROWS(X509_Time("0802010000z", ASN1_Tag::UTC_TIME));