Botan  1.11.15
src/lib/cert/cvc/asn1_eac_tm.cpp
Go to the documentation of this file.
00001 /*
00002 * EAC Time Types
00003 * (C) 2007 FlexSecure GmbH
00004 *     2008-2009 Jack Lloyd
00005 *
00006 * Botan is released under the Simplified BSD License (see license.txt)
00007 */
00008 
00009 #include <botan/eac_asn_obj.h>
00010 #include <botan/der_enc.h>
00011 #include <botan/ber_dec.h>
00012 #include <botan/charset.h>
00013 #include <botan/parsing.h>
00014 #include <botan/internal/rounding.h>
00015 #include <botan/calendar.h>
00016 
00017 namespace Botan {
00018 
00019 namespace {
00020 
00021 std::vector<byte> enc_two_digit(u32bit in)
00022    {
00023    std::vector<byte> result;
00024    in %= 100;
00025    if(in < 10)
00026       result.push_back(0x00);
00027    else
00028       {
00029       u32bit y_first_pos = round_down<u32bit>(in, 10) / 10;
00030       result.push_back(static_cast<byte>(y_first_pos));
00031       }
00032 
00033    u32bit y_sec_pos = in % 10;
00034    result.push_back(static_cast<byte>(y_sec_pos));
00035    return result;
00036    }
00037 
00038 u32bit dec_two_digit(byte b1, byte b2)
00039    {
00040    u32bit upper = b1;
00041    u32bit lower = b2;
00042 
00043    if(upper > 9 || lower > 9)
00044       throw Invalid_Argument("CVC dec_two_digit value too large");
00045 
00046    return upper*10 + lower;
00047    }
00048 
00049 }
00050 
00051 /*
00052 * Create an EAC_Time
00053 */
00054 EAC_Time::EAC_Time(const std::chrono::system_clock::time_point& time,
00055                    ASN1_Tag t) : tag(t)
00056    {
00057    calendar_point cal = calendar_value(time);
00058 
00059    year   = cal.year;
00060    month  = cal.month;
00061    day    = cal.day;
00062    }
00063 
00064 /*
00065 * Create an EAC_Time
00066 */
00067 EAC_Time::EAC_Time(const std::string& t_spec, ASN1_Tag t) : tag(t)
00068    {
00069    set_to(t_spec);
00070    }
00071 
00072 /*
00073 * Create an EAC_Time
00074 */
00075 EAC_Time::EAC_Time(u32bit y, u32bit m, u32bit d, ASN1_Tag t) :
00076    year(y), month(m), day(d), tag(t)
00077    {
00078    }
00079 
00080 /*
00081 * Set the time with a human readable string
00082 */
00083 void EAC_Time::set_to(const std::string& time_str)
00084    {
00085    if(time_str == "")
00086       {
00087       year = month = day = 0;
00088       return;
00089       }
00090 
00091    std::vector<std::string> params;
00092    std::string current;
00093 
00094    for(u32bit j = 0; j != time_str.size(); ++j)
00095       {
00096       if(Charset::is_digit(time_str[j]))
00097          current += time_str[j];
00098       else
00099          {
00100          if(current != "")
00101             params.push_back(current);
00102          current.clear();
00103          }
00104       }
00105    if(current != "")
00106       params.push_back(current);
00107 
00108    if(params.size() != 3)
00109       throw Invalid_Argument("Invalid time specification " + time_str);
00110 
00111    year   = to_u32bit(params[0]);
00112    month  = to_u32bit(params[1]);
00113    day    = to_u32bit(params[2]);
00114 
00115    if(!passes_sanity_check())
00116       throw Invalid_Argument("Invalid time specification " + time_str);
00117    }
00118 
00119 
00120 /*
00121 * DER encode a EAC_Time
00122 */
00123 void EAC_Time::encode_into(DER_Encoder& der) const
00124    {
00125    der.add_object(tag, APPLICATION,
00126                   encoded_eac_time());
00127    }
00128 
00129 /*
00130 * Return a string representation of the time
00131 */
00132 std::string EAC_Time::as_string() const
00133    {
00134    if(time_is_set() == false)
00135       throw Invalid_State("EAC_Time::as_string: No time set");
00136 
00137    return std::to_string(year * 10000 + month * 100 + day);
00138    }
00139 
00140 /*
00141 * Return if the time has been set somehow
00142 */
00143 bool EAC_Time::time_is_set() const
00144    {
00145    return (year != 0);
00146    }
00147 
00148 /*
00149 * Return a human readable string representation
00150 */
00151 std::string EAC_Time::readable_string() const
00152    {
00153    if(time_is_set() == false)
00154       throw Invalid_State("EAC_Time::readable_string: No time set");
00155 
00156    std::string output(11, 0);
00157 
00158    std::sprintf(&output[0], "%04d/%02d/%02d", year, month, day);
00159 
00160    return output;
00161    }
00162 
00163 /*
00164 * Do a general sanity check on the time
00165 */
00166 bool EAC_Time::passes_sanity_check() const
00167    {
00168    if(year < 2000 || year > 2099)
00169       return false;
00170    if(month == 0 || month > 12)
00171       return false;
00172    if(day == 0 || day > 31)
00173       return false;
00174 
00175    return true;
00176    }
00177 
00178 /*
00179 * modification functions
00180 */
00181 void EAC_Time::add_years(u32bit years)
00182    {
00183    year += years;
00184    }
00185 
00186 void EAC_Time::add_months(u32bit months)
00187    {
00188    year += months/12;
00189    month += months % 12;
00190    if(month > 12)
00191       {
00192       year += 1;
00193       month -= 12;
00194       }
00195    }
00196 
00197 /*
00198 * Compare this time against another
00199 */
00200 s32bit EAC_Time::cmp(const EAC_Time& other) const
00201    {
00202    if(time_is_set() == false)
00203       throw Invalid_State("EAC_Time::cmp: No time set");
00204 
00205    const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0;
00206 
00207    if(year < other.year)     return EARLIER;
00208    if(year > other.year)     return LATER;
00209    if(month < other.month)   return EARLIER;
00210    if(month > other.month)   return LATER;
00211    if(day < other.day)       return EARLIER;
00212    if(day > other.day)       return LATER;
00213 
00214    return SAME_TIME;
00215    }
00216 
00217 /*
00218 * Compare two EAC_Times for in various ways
00219 */
00220 bool operator==(const EAC_Time& t1, const EAC_Time& t2)
00221    {
00222    return (t1.cmp(t2) == 0);
00223    }
00224 
00225 bool operator!=(const EAC_Time& t1, const EAC_Time& t2)
00226    {
00227    return (t1.cmp(t2) != 0);
00228    }
00229 
00230 bool operator<=(const EAC_Time& t1, const EAC_Time& t2)
00231    {
00232    return (t1.cmp(t2) <= 0);
00233    }
00234 
00235 bool operator>=(const EAC_Time& t1, const EAC_Time& t2)
00236    {
00237    return (t1.cmp(t2) >= 0);
00238    }
00239 
00240 bool operator>(const EAC_Time& t1, const EAC_Time& t2)
00241    {
00242    return (t1.cmp(t2) > 0);
00243    }
00244 
00245 bool operator<(const EAC_Time& t1, const EAC_Time& t2)
00246    {
00247    return (t1.cmp(t2) < 0);
00248    }
00249 
00250 /*
00251 * Decode a BER encoded EAC_Time
00252 */
00253 void EAC_Time::decode_from(BER_Decoder& source)
00254    {
00255    BER_Object obj = source.get_next_object();
00256 
00257    if(obj.type_tag != this->tag)
00258       throw BER_Decoding_Error("Tag mismatch when decoding");
00259 
00260    if(obj.value.size() != 6)
00261       {
00262       throw Decoding_Error("EAC_Time decoding failed");
00263       }
00264 
00265    try
00266       {
00267       u32bit tmp_year = dec_two_digit(obj.value[0], obj.value[1]);
00268       u32bit tmp_mon = dec_two_digit(obj.value[2], obj.value[3]);
00269       u32bit tmp_day = dec_two_digit(obj.value[4], obj.value[5]);
00270       year = tmp_year + 2000;
00271       month = tmp_mon;
00272       day = tmp_day;
00273       }
00274    catch (Invalid_Argument)
00275       {
00276       throw Decoding_Error("EAC_Time decoding failed");
00277       }
00278 
00279    }
00280 
00281 /*
00282 * make the value an octet string for encoding
00283 */
00284 std::vector<byte> EAC_Time::encoded_eac_time() const
00285    {
00286    std::vector<byte> result;
00287    result += enc_two_digit(year);
00288    result += enc_two_digit(month);
00289    result += enc_two_digit(day);
00290    return result;
00291    }
00292 
00293 }