Botan
1.11.15
|
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 }