monotone

monotone Mtn Source Tree

Root/botan/asn1_tm.cpp

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

Archive Download this file

Branches

Tags

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