diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/asn1/asn1_time.cpp | 31 | ||||
-rw-r--r-- | src/lib/utils/exceptn.h | 11 | ||||
-rw-r--r-- | src/tests/catchy/test_x509.cpp | 80 |
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)); |