Botan  1.11.15
src/lib/asn1/asn1_time.cpp
Go to the documentation of this file.
00001 /*
00002 * X.509 Time Types
00003 * (C) 1999-2007 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/asn1_time.h>
00009 #include <botan/der_enc.h>
00010 #include <botan/ber_dec.h>
00011 #include <botan/charset.h>
00012 #include <botan/parsing.h>
00013 #include <botan/calendar.h>
00014 
00015 namespace Botan {
00016 
00017 /*
00018 * Create an X509_Time
00019 */
00020 X509_Time::X509_Time(const std::string& time_str)
00021    {
00022    set_to(time_str);
00023    }
00024 
00025 /*
00026 * Create a X509_Time from a time point
00027 */
00028 X509_Time::X509_Time(const std::chrono::system_clock::time_point& time)
00029    {
00030    calendar_point cal = calendar_value(time);
00031 
00032    year   = cal.year;
00033    month  = cal.month;
00034    day    = cal.day;
00035    hour   = cal.hour;
00036    minute = cal.minutes;
00037    second = cal.seconds;
00038 
00039    tag = (year >= 2050) ? GENERALIZED_TIME : UTC_TIME;
00040    }
00041 
00042 /*
00043 * Create an X509_Time
00044 */
00045 X509_Time::X509_Time(const std::string& t_spec, ASN1_Tag t) : tag(t)
00046    {
00047    set_to(t_spec, tag);
00048    }
00049 
00050 /*
00051 * Set the time with a human readable string
00052 */
00053 void X509_Time::set_to(const std::string& time_str)
00054    {
00055    if(time_str == "")
00056       {
00057       year = month = day = hour = minute = second = 0;
00058       tag = NO_OBJECT;
00059       return;
00060       }
00061 
00062    std::vector<std::string> params;
00063    std::string current;
00064 
00065    for(size_t j = 0; j != time_str.size(); ++j)
00066       {
00067       if(Charset::is_digit(time_str[j]))
00068          current += time_str[j];
00069       else
00070          {
00071          if(current != "")
00072             params.push_back(current);
00073          current.clear();
00074          }
00075       }
00076    if(current != "")
00077       params.push_back(current);
00078 
00079    if(params.size() < 3 || params.size() > 6)
00080       throw Invalid_Argument("Invalid time specification " + time_str);
00081 
00082    year   = to_u32bit(params[0]);
00083    month  = to_u32bit(params[1]);
00084    day    = to_u32bit(params[2]);
00085    hour   = (params.size() >= 4) ? to_u32bit(params[3]) : 0;
00086    minute = (params.size() >= 5) ? to_u32bit(params[4]) : 0;
00087    second = (params.size() == 6) ? to_u32bit(params[5]) : 0;
00088 
00089    tag = (year >= 2050) ? GENERALIZED_TIME : UTC_TIME;
00090 
00091    if(!passes_sanity_check())
00092       throw Invalid_Argument("Invalid time specification " + time_str);
00093    }
00094 
00095 /*
00096 * Set the time with an ISO time format string
00097 */
00098 void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
00099    {
00100    if(spec_tag == GENERALIZED_TIME)
00101       {
00102       if(t_spec.size() != 13 && t_spec.size() != 15)
00103          throw Invalid_Argument("Invalid GeneralizedTime: " + t_spec);
00104       }
00105    else if(spec_tag == UTC_TIME)
00106       {
00107       if(t_spec.size() != 11 && t_spec.size() != 13)
00108          throw Invalid_Argument("Invalid UTCTime: " + t_spec);
00109       }
00110    else
00111       {
00112       throw Invalid_Argument("Invalid time tag " + std::to_string(spec_tag) + " val " + t_spec);
00113       }
00114 
00115    if(t_spec[t_spec.size()-1] != 'Z')
00116       throw Invalid_Argument("Invalid time encoding: " + t_spec);
00117 
00118    const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4;
00119 
00120    std::vector<std::string> params;
00121    std::string current;
00122 
00123    for(size_t j = 0; j != YEAR_SIZE; ++j)
00124       current += t_spec[j];
00125    params.push_back(current);
00126    current.clear();
00127 
00128    for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j)
00129       {
00130       current += t_spec[j];
00131       if(current.size() == 2)
00132          {
00133          params.push_back(current);
00134          current.clear();
00135          }
00136       }
00137 
00138    year   = to_u32bit(params[0]);
00139    month  = to_u32bit(params[1]);
00140    day    = to_u32bit(params[2]);
00141    hour   = to_u32bit(params[3]);
00142    minute = to_u32bit(params[4]);
00143    second = (params.size() == 6) ? to_u32bit(params[5]) : 0;
00144    tag    = spec_tag;
00145 
00146    if(spec_tag == UTC_TIME)
00147       {
00148       if(year >= 50) year += 1900;
00149       else           year += 2000;
00150       }
00151 
00152    if(!passes_sanity_check())
00153       throw Invalid_Argument("Invalid time specification " + t_spec);
00154    }
00155 
00156 /*
00157 * DER encode a X509_Time
00158 */
00159 void X509_Time::encode_into(DER_Encoder& der) const
00160    {
00161    if(tag != GENERALIZED_TIME && tag != UTC_TIME)
00162       throw Invalid_Argument("X509_Time: Bad encoding tag");
00163 
00164    der.add_object(tag, UNIVERSAL,
00165                   Charset::transcode(as_string(),
00166                                      LOCAL_CHARSET,
00167                                      LATIN1_CHARSET));
00168    }
00169 
00170 /*
00171 * Decode a BER encoded X509_Time
00172 */
00173 void X509_Time::decode_from(BER_Decoder& source)
00174    {
00175    BER_Object ber_time = source.get_next_object();
00176 
00177    set_to(Charset::transcode(ASN1::to_string(ber_time),
00178                              LATIN1_CHARSET,
00179                              LOCAL_CHARSET),
00180           ber_time.type_tag);
00181    }
00182 
00183 /*
00184 * Return a string representation of the time
00185 */
00186 std::string X509_Time::as_string() const
00187    {
00188    if(time_is_set() == false)
00189       throw Invalid_State("X509_Time::as_string: No time set");
00190 
00191    u32bit full_year = year;
00192 
00193    if(tag == UTC_TIME)
00194       {
00195       if(year < 1950 || year >= 2050)
00196          throw Encoding_Error("X509_Time: The time " + readable_string() +
00197                               " cannot be encoded as a UTCTime");
00198 
00199       full_year = (year >= 2000) ? (year - 2000) : (year - 1900);
00200       }
00201 
00202    std::string repr = std::to_string(full_year*10000000000 +
00203                                      month*100000000 +
00204                                      day*1000000 +
00205                                      hour*10000 +
00206                                      minute*100 +
00207                                      second) + "Z";
00208 
00209    u32bit desired_size = (tag == UTC_TIME) ? 13 : 15;
00210 
00211    while(repr.size() < desired_size)
00212       repr = "0" + repr;
00213 
00214    return repr;
00215    }
00216 
00217 /*
00218 * Return if the time has been set somehow
00219 */
00220 bool X509_Time::time_is_set() const
00221    {
00222    return (year != 0);
00223    }
00224 
00225 /*
00226 * Return a human readable string representation
00227 */
00228 std::string X509_Time::readable_string() const
00229    {
00230    if(time_is_set() == false)
00231       throw Invalid_State("X509_Time::readable_string: No time set");
00232 
00233    std::string output(24, 0);
00234 
00235    std::sprintf(&output[0], "%04d/%02d/%02d %02d:%02d:%02d UTC",
00236                 year, month, day, hour, minute, second);
00237 
00238    output.resize(23); // remove trailing null
00239 
00240    return output;
00241    }
00242 
00243 /*
00244 * Do a general sanity check on the time
00245 */
00246 bool X509_Time::passes_sanity_check() const
00247    {
00248    if(year < 1950 || year > 2100)
00249       return false;
00250    if(month == 0 || month > 12)
00251       return false;
00252    if(day == 0 || day > 31)
00253       return false;
00254    if(hour >= 24 || minute > 60 || second > 60)
00255       return false;
00256    return true;
00257    }
00258 
00259 /*
00260 * Compare this time against another
00261 */
00262 s32bit X509_Time::cmp(const X509_Time& other) const
00263    {
00264    if(time_is_set() == false)
00265       throw Invalid_State("X509_Time::cmp: No time set");
00266 
00267    const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0;
00268 
00269    if(year < other.year)     return EARLIER;
00270    if(year > other.year)     return LATER;
00271    if(month < other.month)   return EARLIER;
00272    if(month > other.month)   return LATER;
00273    if(day < other.day)       return EARLIER;
00274    if(day > other.day)       return LATER;
00275    if(hour < other.hour)     return EARLIER;
00276    if(hour > other.hour)     return LATER;
00277    if(minute < other.minute) return EARLIER;
00278    if(minute > other.minute) return LATER;
00279    if(second < other.second) return EARLIER;
00280    if(second > other.second) return LATER;
00281 
00282    return SAME_TIME;
00283    }
00284 
00285 /*
00286 * Compare two X509_Times for in various ways
00287 */
00288 bool operator==(const X509_Time& t1, const X509_Time& t2)
00289    { return (t1.cmp(t2) == 0); }
00290 bool operator!=(const X509_Time& t1, const X509_Time& t2)
00291    { return (t1.cmp(t2) != 0); }
00292 
00293 bool operator<=(const X509_Time& t1, const X509_Time& t2)
00294    { return (t1.cmp(t2) <= 0); }
00295 bool operator>=(const X509_Time& t1, const X509_Time& t2)
00296    { return (t1.cmp(t2) >= 0); }
00297 
00298 bool operator<(const X509_Time& t1, const X509_Time& t2)
00299    { return (t1.cmp(t2) < 0); }
00300 bool operator>(const X509_Time& t1, const X509_Time& t2)
00301    { return (t1.cmp(t2) > 0); }
00302 
00303 }