diff options
Diffstat (limited to 'botan/src/cert/cvc/asn1_eac_tm.cpp')
-rw-r--r-- | botan/src/cert/cvc/asn1_eac_tm.cpp | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/botan/src/cert/cvc/asn1_eac_tm.cpp b/botan/src/cert/cvc/asn1_eac_tm.cpp new file mode 100644 index 0000000..05533b5 --- /dev/null +++ b/botan/src/cert/cvc/asn1_eac_tm.cpp @@ -0,0 +1,361 @@ +/* +* EAC Time Types +* (C) 2007 FlexSecure GmbH +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/eac_asn_obj.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/charset.h> +#include <botan/parsing.h> +#include <ctime> +#include <sstream> + +namespace Botan { + +namespace { + +/* +* Convert a time_t to a struct tm +*/ +std::tm get_tm(u64bit timer) + { + std::time_t time_val = static_cast<std::time_t>(timer); + + std::tm* tm_p = std::gmtime(&time_val); + if (tm_p == 0) + throw Encoding_Error("EAC_Time: gmtime could not encode " + + to_string(timer)); + return (*tm_p); + } +SecureVector<byte> enc_two_digit(u32bit in) + { + SecureVector<byte> result; + in %= 100; + if (in < 10) + { + result.append(0x00); + } + else + { + u32bit y_first_pos = (in - (in%10))/10; + result.append(static_cast<byte>(y_first_pos)); + } + u32bit y_sec_pos = in%10; + result.append(static_cast<byte>(y_sec_pos)); + return result; + } +u32bit dec_two_digit(byte b1, byte b2) + { + u32bit upper = (u32bit)b1; + u32bit lower = (u32bit)b2; + if (upper > 9 || lower > 9) + { + throw Invalid_Argument("u32bit dec_two_digit(byte b1, byte b2): value too large"); + } + return upper*10 + lower; + + } +} + +/* +* Create an EAC_Time +*/ +EAC_Time::EAC_Time(u64bit timer, ASN1_Tag t) + :tag(t) + { + std::tm time_info = get_tm(timer); + + year = time_info.tm_year + 1900; + month = time_info.tm_mon + 1; + day = time_info.tm_mday; + + } + +/* +* Create an EAC_Time +*/ +EAC_Time::EAC_Time(const std::string& t_spec, ASN1_Tag t) + :tag(t) + { + set_to(t_spec); + } +/* +* Create an EAC_Time +*/ +EAC_Time::EAC_Time(u32bit y, u32bit m, u32bit d, ASN1_Tag t) + : year(y), + month(m), + day(d), + tag(t) + { + } + +/* +* Set the time with a human readable string +*/ +void EAC_Time::set_to(const std::string& time_str) + { + if (time_str == "") + { + year = month = day = 0; + return; + } + + std::vector<std::string> params; + std::string current; + + for (u32bit j = 0; j != time_str.size(); ++j) + { + if (Charset::is_digit(time_str[j])) + current += time_str[j]; + else + { + if (current != "") + params.push_back(current); + current.clear(); + } + } + if (current != "") + params.push_back(current); + + if (params.size() != 3) + throw Invalid_Argument("Invalid time specification " + time_str); + + year = to_u32bit(params[0]); + month = to_u32bit(params[1]); + day = to_u32bit(params[2]); + + if (!passes_sanity_check()) + throw Invalid_Argument("Invalid time specification " + time_str); + } + + +/* +* DER encode a EAC_Time +*/ +void EAC_Time::encode_into(DER_Encoder& der) const + { + der.add_object(tag, APPLICATION, + encoded_eac_time()); + } + +/* +* Return a string representation of the time +*/ +std::string EAC_Time::as_string() const + { + if (time_is_set() == false) + throw Invalid_State("EAC_Time::as_string: No time set"); + + std::string asn1rep; + asn1rep = to_string(year, 2); + + asn1rep += to_string(month, 2) + to_string(day, 2); + + return asn1rep; + } + +/* +* Return if the time has been set somehow +*/ +bool EAC_Time::time_is_set() const + { + return (year != 0); + } + +/* +* Return a human readable string representation +*/ +std::string EAC_Time::readable_string() const + { + if (time_is_set() == false) + throw Invalid_State("EAC_Time::readable_string: No time set"); + + std::string readable; + readable += to_string(year, 2) + "/"; + readable += to_string(month, 2) + "/"; + readable += to_string(day, 2) + " "; + + return readable; + } + +/* +* Do a general sanity check on the time +*/ +bool EAC_Time::passes_sanity_check() const + { + if (year < 2000 || year > 2099) + return false; + if (month == 0 || month > 12) + return false; + if (day == 0 || day > 31) + return false; + + return true; + } + +/****************************************** +* modification functions +******************************************/ + +void EAC_Time::add_years(u32bit years) + { + year += years; + } +void EAC_Time::add_months(u32bit months) + { + year += months/12; + month += months % 12; + if(month > 12) + { + year += 1; + month -= 12; + } + } + + +/* +* Compare this time against another +*/ +s32bit EAC_Time::cmp(const EAC_Time& other) const + { + if (time_is_set() == false) + throw Invalid_State("EAC_Time::cmp: No time set"); + + const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0; + + if (year < other.year) return EARLIER; + if (year > other.year) return LATER; + if (month < other.month) return EARLIER; + if (month > other.month) return LATER; + if (day < other.day) return EARLIER; + if (day > other.day) return LATER; + + return SAME_TIME; + } + +/* +* Compare two EAC_Times for in various ways +*/ +bool operator==(const EAC_Time& t1, const EAC_Time& t2) + { + return (t1.cmp(t2) == 0); + } +bool operator!=(const EAC_Time& t1, const EAC_Time& t2) + { + return (t1.cmp(t2) != 0); + } +bool operator<=(const EAC_Time& t1, const EAC_Time& t2) + { + return (t1.cmp(t2) <= 0); + } +bool operator>=(const EAC_Time& t1, const EAC_Time& t2) + { + return (t1.cmp(t2) >= 0); + } +bool operator>(const EAC_Time& t1, const EAC_Time& t2) + { + return (t1.cmp(t2) > 0); + } +bool operator<(const EAC_Time& t1, const EAC_Time& t2) + { + return (t1.cmp(t2) < 0); + } + +/* +* Decode a BER encoded EAC_Time +*/ +void EAC_Time::decode_from(BER_Decoder& source) + { + BER_Object obj = source.get_next_object(); + if (obj.type_tag != this->tag) + { + std::string message("decoding type mismatch for EAC_Time, tag is "); + std::stringstream ss; + std::string str_is; + ss << std::hex << obj.type_tag; + ss >> str_is; + message.append(str_is); + message.append(", while it should be "); + std::stringstream ss2; + std::string str_should; + ss2 << std::hex << this->tag; + ss2 >> str_should; + message.append(str_should); + throw Decoding_Error(message); + + } + if (obj.value.size() != 6) + { + throw Decoding_Error("EAC_Time decoding failed"); + } + try + { + u32bit tmp_year = dec_two_digit(obj.value[0], obj.value[1]); + u32bit tmp_mon = dec_two_digit(obj.value[2], obj.value[3]); + u32bit tmp_day = dec_two_digit(obj.value[4], obj.value[5]); + year = tmp_year + 2000; + month = tmp_mon; + day = tmp_day; + } + catch (Invalid_Argument) + { + throw Decoding_Error("EAC_Time decoding failed"); + } + + } + +u32bit EAC_Time::get_year() const + { + return year; + } +u32bit EAC_Time::get_month() const + { + return month; + } +u32bit EAC_Time::get_day() const + { + return day; + } + +/* +* make the value an octet string for encoding +*/ +SecureVector<byte> EAC_Time::encoded_eac_time() const + { + SecureVector<byte> result; + result.append(enc_two_digit(year)); + result.append(enc_two_digit(month)); + result.append(enc_two_digit(day)); + return result; + } + +ASN1_Ced::ASN1_Ced(std::string const& str) + : EAC_Time(str, ASN1_Tag(37)) + {} + +ASN1_Ced::ASN1_Ced(u64bit val) + : EAC_Time(val, ASN1_Tag(37)) + {} + +ASN1_Ced::ASN1_Ced(EAC_Time const& other) + : EAC_Time(other.get_year(), other.get_month(), other.get_day(), ASN1_Tag(37)) + {} + +ASN1_Cex::ASN1_Cex(std::string const& str) + : EAC_Time(str, ASN1_Tag(36)) + {} + +ASN1_Cex::ASN1_Cex(u64bit val) + : EAC_Time(val, ASN1_Tag(36)) + {} + +ASN1_Cex::ASN1_Cex(EAC_Time const& other) + : EAC_Time(other.get_year(), other.get_month(), other.get_day(), ASN1_Tag(36)) + {} + +} |