monotone

monotone Mtn Source Tree

Root/botan/asn1_tm.cpp

1/*************************************************
2* X.509 Time Types Source File *
3* (C) 1999-2007 The Botan Project *
4*************************************************/
5
6#include <botan/asn1_obj.h>
7#include <botan/der_enc.h>
8#include <botan/ber_dec.h>
9#include <botan/charset.h>
10#include <botan/parsing.h>
11#include <botan/config.h>
12#include <ctime>
13
14namespace Botan {
15
16namespace {
17
18/*************************************************
19* Convert a time_t to a struct tm *
20*************************************************/
21std::tm get_tm(u64bit timer)
22 {
23 std::time_t time_val = static_cast<std::time_t>(timer);
24
25 std::tm* tm_p = std::gmtime(&time_val);
26 if(tm_p == 0)
27 throw Encoding_Error("X509_Time: gmtime could not encode " +
28 to_string(timer));
29 return (*tm_p);
30 }
31
32}
33
34/*************************************************
35* Create an X509_Time *
36*************************************************/
37X509_Time::X509_Time(const std::string& time_str)
38 {
39 set_to(time_str);
40 }
41
42/*************************************************
43* Create an X509_Time *
44*************************************************/
45X509_Time::X509_Time(u64bit timer)
46 {
47 std::tm time_info = get_tm(timer);
48
49 year = time_info.tm_year + 1900;
50 month = time_info.tm_mon + 1;
51 day = time_info.tm_mday;
52 hour = time_info.tm_hour;
53 minute = time_info.tm_min;
54 second = time_info.tm_sec;
55
56 if(year >= 2050)
57 tag = GENERALIZED_TIME;
58 else
59 tag = UTC_TIME;
60 }
61
62/*************************************************
63* Create an X509_Time *
64*************************************************/
65X509_Time::X509_Time(const std::string& t_spec, ASN1_Tag t) : tag(t)
66 {
67 set_to(t_spec, tag);
68 }
69
70/*************************************************
71* Set the time with a human readable string *
72*************************************************/
73void X509_Time::set_to(const std::string& time_str)
74 {
75 if(time_str == "")
76 {
77 year = month = day = hour = minute = second = 0;
78 return;
79 }
80
81 std::vector<std::string> params;
82 std::string current;
83
84 for(u32bit j = 0; j != time_str.size(); ++j)
85 {
86 if(Charset::is_digit(time_str[j]))
87 current += time_str[j];
88 else
89 {
90 if(current != "")
91 params.push_back(current);
92 current.clear();
93 }
94 }
95 if(current != "")
96 params.push_back(current);
97
98 if(params.size() < 3 || params.size() > 6)
99 throw Invalid_Argument("Invalid time specification " + time_str);
100
101 year = to_u32bit(params[0]);
102 month = to_u32bit(params[1]);
103 day = to_u32bit(params[2]);
104 hour = (params.size() >= 4) ? to_u32bit(params[3]) : 0;
105 minute = (params.size() >= 5) ? to_u32bit(params[4]) : 0;
106 second = (params.size() == 6) ? to_u32bit(params[5]) : 0;
107
108 if(year >= 2050)
109 tag = GENERALIZED_TIME;
110 else
111 tag = UTC_TIME;
112
113 if(!passes_sanity_check())
114 throw Invalid_Argument("Invalid time specification " + time_str);
115 }
116
117/*************************************************
118* Set the time with an ISO time format string *
119*************************************************/
120void X509_Time::set_to(const std::string& t_spec, ASN1_Tag tag)
121 {
122 if(tag != GENERALIZED_TIME && tag != UTC_TIME)
123 throw Invalid_Argument("X509_Time: Invalid tag " + to_string(tag));
124 if(tag == GENERALIZED_TIME && t_spec.size() != 13 && t_spec.size() != 15)
125 throw Invalid_Argument("Invalid GeneralizedTime: " + t_spec);
126 if(tag == UTC_TIME && t_spec.size() != 11 && t_spec.size() != 13)
127 throw Invalid_Argument("Invalid UTCTime: " + t_spec);
128 if(t_spec[t_spec.size()-1] != 'Z')
129 throw Invalid_Argument("Invalid time encoding: " + t_spec);
130
131 const u32bit YEAR_SIZE = (tag == UTC_TIME) ? 2 : 4;
132
133 std::vector<std::string> params;
134 std::string current;
135
136 for(u32bit j = 0; j != YEAR_SIZE; ++j)
137 current += t_spec[j];
138 params.push_back(current);
139 current.clear();
140
141 for(u32bit j = YEAR_SIZE; j != t_spec.size() - 1; ++j)
142 {
143 current += t_spec[j];
144 if(current.size() == 2)
145 {
146 params.push_back(current);
147 current.clear();
148 }
149 }
150
151 year = to_u32bit(params[0]);
152 month = to_u32bit(params[1]);
153 day = to_u32bit(params[2]);
154 hour = to_u32bit(params[3]);
155 minute = to_u32bit(params[4]);
156 second = (params.size() == 6) ? to_u32bit(params[5]) : 0;
157
158 if(tag == UTC_TIME)
159 {
160 if(year >= 50) year += 1900;
161 else year += 2000;
162 }
163
164 if(!passes_sanity_check())
165 throw Invalid_Argument("Invalid time specification " + t_spec);
166 }
167
168/*************************************************
169* DER encode a X509_Time *
170*************************************************/
171void X509_Time::encode_into(DER_Encoder& der) const
172 {
173 if(tag != GENERALIZED_TIME && tag != UTC_TIME)
174 throw Invalid_Argument("X509_Time: Bad encoding tag");
175 der.add_object(tag, UNIVERSAL,
176 Charset::transcode(as_string(),
177 LOCAL_CHARSET, LATIN1_CHARSET));
178 }
179
180/*************************************************
181* Return a string representation of the time *
182*************************************************/
183std::string X509_Time::as_string() const
184 {
185 if(time_is_set() == false)
186 throw Invalid_State("X509_Time::as_string: No time set");
187
188 std::string asn1rep;
189 if(tag == GENERALIZED_TIME)
190 asn1rep = to_string(year, 4);
191 else
192 {
193 if(year < 1950 || year >= 2050)
194 throw Encoding_Error("X509_Time: The time " + readable_string() +
195 " cannot be encoded as a UTCTime");
196 u32bit asn1year = (year >= 2000) ? (year - 2000) : (year - 1900);
197 asn1rep = to_string(asn1year, 2);
198 }
199 asn1rep += to_string(month, 2) + to_string(day, 2);
200 asn1rep += to_string(hour, 2) + to_string(minute, 2) + to_string(second, 2);
201 asn1rep += "Z";
202 return asn1rep;
203 }
204
205/*************************************************
206* Return if the time has been set somehow *
207*************************************************/
208bool X509_Time::time_is_set() const
209 {
210 return (year != 0);
211 }
212
213/*************************************************
214* Return a human readable string representation *
215*************************************************/
216std::string X509_Time::readable_string() const
217 {
218 if(time_is_set() == false)
219 throw Invalid_State("X509_Time::readable_string: No time set");
220
221 std::string readable;
222 readable += to_string(year, 4) + "/";
223 readable += to_string(month ) + "/";
224 readable += to_string(day ) + " ";
225 readable += to_string(hour ) + ":";
226 readable += to_string(minute, 2) + ":";
227 readable += to_string(second, 2) + " UTC";
228 return readable;
229 }
230
231/*************************************************
232* Do a general sanity check on the time *
233*************************************************/
234bool X509_Time::passes_sanity_check() const
235 {
236 if(year < 1950 || year > 2100)
237 return false;
238 if(month == 0 || month > 12)
239 return false;
240 if(day == 0 || day > 31)
241 return false;
242 if(hour >= 24 || minute > 60 || second > 60)
243 return false;
244 return true;
245 }
246
247/*************************************************
248* Compare this time against another *
249*************************************************/
250s32bit X509_Time::cmp(const X509_Time& other) const
251 {
252 if(time_is_set() == false)
253 throw Invalid_State("X509_Time::cmp: No time set");
254
255 const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0;
256
257 if(year < other.year) return EARLIER;
258 if(year > other.year) return LATER;
259 if(month < other.month) return EARLIER;
260 if(month > other.month) return LATER;
261 if(day < other.day) return EARLIER;
262 if(day > other.day) return LATER;
263 if(hour < other.hour) return EARLIER;
264 if(hour > other.hour) return LATER;
265 if(minute < other.minute) return EARLIER;
266 if(minute > other.minute) return LATER;
267 if(second < other.second) return EARLIER;
268 if(second > other.second) return LATER;
269
270 return SAME_TIME;
271 }
272
273/*************************************************
274* Compare two X509_Times for in various ways *
275*************************************************/
276bool operator==(const X509_Time& t1, const X509_Time& t2)
277 { return (t1.cmp(t2) == 0); }
278bool operator!=(const X509_Time& t1, const X509_Time& t2)
279 { return (t1.cmp(t2) != 0); }
280bool operator<=(const X509_Time& t1, const X509_Time& t2)
281 { return (t1.cmp(t2) <= 0); }
282bool operator>=(const X509_Time& t1, const X509_Time& t2)
283 { return (t1.cmp(t2) >= 0); }
284
285/*************************************************
286* Do a validity check *
287*************************************************/
288s32bit validity_check(const X509_Time& start, const X509_Time& end,
289 u64bit current_time)
290 {
291 const u32bit ALLOWABLE_SLIP =
292 global_config().option_as_time("x509/validity_slack");
293
294 const s32bit NOT_YET_VALID = -1, VALID_TIME = 0, EXPIRED = 1;
295
296 if(start.cmp(current_time + ALLOWABLE_SLIP) > 0)
297 return NOT_YET_VALID;
298 if(end.cmp(current_time - ALLOWABLE_SLIP) < 0)
299 return EXPIRED;
300 return VALID_TIME;
301 }
302
303/*************************************************
304* Decode a BER encoded X509_Time *
305*************************************************/
306void X509_Time::decode_from(BER_Decoder& source)
307 {
308 BER_Object ber_time = source.get_next_object();
309 set_to(Charset::transcode(ASN1::to_string(ber_time),
310 LATIN1_CHARSET, LOCAL_CHARSET),
311 ber_time.type_tag);
312 }
313
314}

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status