Botan 2.1.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

asn1_time.cpp
Go to the documentation of this file.
1 /*
2 * X.509 Time Types
3 * (C) 1999-2007 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7
8 #include <botan/asn1_time.h>
9 #include <botan/der_enc.h>
10 #include <botan/ber_dec.h>
11 #include <botan/charset.h>
12 #include <botan/exceptn.h>
13 #include <botan/parsing.h>
14 #include <botan/calendar.h>
15 #include <sstream>
16 #include <iomanip>
17
18 namespace Botan {
19
20 X509_Time::X509_Time(const std::chrono::system_clock::time_point& time)
21 {
22 calendar_point cal = calendar_value(time);
23
24 m_year = cal.year;
25 m_month = cal.month;
26 m_day = cal.day;
27 m_hour = cal.hour;
28 m_minute = cal.minutes;
29 m_second = cal.seconds;
30
31 m_tag = (m_year >= 2050) ? GENERALIZED_TIME : UTC_TIME;
32 }
33
34 X509_Time::X509_Time(const std::string& t_spec, ASN1_Tag tag)
35 {
36 set_to(t_spec, tag);
37 }
38
39 void X509_Time::encode_into(DER_Encoder& der) const
40 {
41 if(m_tag != GENERALIZED_TIME && m_tag != UTC_TIME)
42 throw Invalid_Argument("X509_Time: Bad encoding tag");
43
44 der.add_object(m_tag, UNIVERSAL,
45 Charset::transcode(to_string(),
46 LOCAL_CHARSET,
47 LATIN1_CHARSET));
48 }
49
50 void X509_Time::decode_from(BER_Decoder& source)
51 {
52 BER_Object ber_time = source.get_next_object();
53
54 set_to(Charset::transcode(ASN1::to_string(ber_time),
55 LATIN1_CHARSET,
56 LOCAL_CHARSET),
57 ber_time.type_tag);
58 }
59
60 std::string X509_Time::to_string() const
61 {
62 if(time_is_set() == false)
63 throw Invalid_State("X509_Time::as_string: No time set");
64
65 uint32_t full_year = m_year;
66
67 if(m_tag == UTC_TIME)
68 {
69 if(m_year < 1950 || m_year >= 2050)
70 throw Encoding_Error("X509_Time: The time " + readable_string() +
71 " cannot be encoded as a UTCTime");
72
73 full_year = (m_year >= 2000) ? (m_year - 2000) : (m_year - 1900);
74 }
75
76 const auto factor_y = uint64_t{10000000000ull}; // literal exceeds 32bit int range
77 const auto factor_m = uint64_t{100000000ull};
78 const auto factor_d = uint64_t{1000000ull};
79 const auto factor_h = uint64_t{10000ull};
80 const auto factor_i = uint64_t{100ull};
81
82 std::string repr = std::to_string(factor_y * full_year +
83 factor_m * m_month +
84 factor_d * m_day +
85 factor_h * m_hour +
86 factor_i * m_minute +
87 m_second) + "Z";
88
89 uint32_t desired_size = (m_tag == UTC_TIME) ? 13 : 15;
90
91 while(repr.size() < desired_size)
92 repr = "0" + repr;
93
94 return repr;
95 }
96
97 std::string X509_Time::readable_string() const
98 {
99 if(time_is_set() == false)
100 throw Invalid_State("X509_Time::readable_string: No time set");
101
102 // desired format: "%04d/%02d/%02d %02d:%02d:%02d UTC"
103 std::stringstream output;
104 {
105 using namespace std;
106 output << setfill('0')
107 << setw(4) << m_year << "/" << setw(2) << m_month << "/" << setw(2) << m_day
108 << " "
109 << setw(2) << m_hour << ":" << setw(2) << m_minute << ":" << setw(2) << m_second
110 << " UTC";
111 }
112 return output.str();
113 }
114
115 bool X509_Time::time_is_set() const
116 {
117 return (m_year != 0);
118 }
119
120 int32_t X509_Time::cmp(const X509_Time& other) const
121 {
122 if(time_is_set() == false)
123 throw Invalid_State("X509_Time::cmp: No time set");
124
125 const int32_t EARLIER = -1, LATER = 1, SAME_TIME = 0;
126
127 if(m_year < other.m_year) return EARLIER;
128 if(m_year > other.m_year) return LATER;
129 if(m_month < other.m_month) return EARLIER;
130 if(m_month > other.m_month) return LATER;
131 if(m_day < other.m_day) return EARLIER;
132 if(m_day > other.m_day) return LATER;
133 if(m_hour < other.m_hour) return EARLIER;
134 if(m_hour > other.m_hour) return LATER;
135 if(m_minute < other.m_minute) return EARLIER;
136 if(m_minute > other.m_minute) return LATER;
137 if(m_second < other.m_second) return EARLIER;
138 if(m_second > other.m_second) return LATER;
139
140 return SAME_TIME;
141 }
142
143 void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
144 {
145 if(spec_tag == UTC_OR_GENERALIZED_TIME)
146 {
147 try
148 {
149 set_to(t_spec, GENERALIZED_TIME);
150 return;
151 }
152 catch(Invalid_Argument&) {} // Not a generalized time. Continue
153
154 try
155 {
156 set_to(t_spec, UTC_TIME);
157 return;
158 }
159 catch(Invalid_Argument&) {} // Not a UTC time. Continue
160
161 throw Invalid_Argument("Time string could not be parsed as GeneralizedTime or UTCTime.");
162 }
163
164 BOTAN_ASSERT(spec_tag == UTC_TIME || spec_tag == GENERALIZED_TIME, "Invalid tag.");
165
166 if(t_spec.empty())
167 throw Invalid_Argument("Time string must not be empty.");
168
169 if(t_spec.back() != 'Z')
170 throw Unsupported_Argument("Botan does not support times with timezones other than Z: " + t_spec);
171
172 if(spec_tag == GENERALIZED_TIME)
173 {
174 if(t_spec.size() != 15)
175 throw Invalid_Argument("Invalid GeneralizedTime string: '" + t_spec + "'");
176 }
177 else if(spec_tag == UTC_TIME)
178 {
179 if(t_spec.size() != 13)
180 throw Invalid_Argument("Invalid UTCTime string: '" + t_spec + "'");
181 }
182
183 const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4;
184
185 std::vector<std::string> params;
186 std::string current;
187
188 for(size_t j = 0; j != YEAR_SIZE; ++j)
189 current += t_spec[j];
190 params.push_back(current);
191 current.clear();
192
193 for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j)
194 {
195 current += t_spec[j];
196 if(current.size() == 2)
197 {
198 params.push_back(current);
199 current.clear();
200 }
201 }
202
203 m_year = to_u32bit(params[0]);
204 m_month = to_u32bit(params[1]);
205 m_day = to_u32bit(params[2]);
206 m_hour = to_u32bit(params[3]);
207 m_minute = to_u32bit(params[4]);
208 m_second = (params.size() == 6) ? to_u32bit(params[5]) : 0;
209 m_tag = spec_tag;
210
211 if(spec_tag == UTC_TIME)
212 {
213 if(m_year >= 50) m_year += 1900;
214 else m_year += 2000;
215 }
216
217 if(!passes_sanity_check())
218 throw Invalid_Argument("Time did not pass sanity check: " + t_spec);
219 }
220
221 /*
222 * Do a general sanity check on the time
223 */
224 bool X509_Time::passes_sanity_check() const
225 {
226 if(m_year < 1950 || m_year > 2100)
227 return false;
228 if(m_month == 0 || m_month > 12)
229 return false;
230 if(m_day == 0 || m_day > 31)
231 return false;
232 if(m_hour >= 24 || m_minute > 60 || m_second > 60)
233 return false;
234
235 if (m_tag == UTC_TIME)
236 {
237 /*
238 UTCTime limits the value of components such that leap seconds
239 are not covered. See "UNIVERSAL 23" in "Information technology
240 Abstract Syntax Notation One (ASN.1): Specification of basic notation"
241
242 http://www.itu.int/ITU-T/studygroups/com17/languages/
243 */
244 if (m_hour > 23 || m_minute > 59 || m_second > 59)
245 {
246 return false;
247 }
248 }
249
250 return true;
251 }
252
253 std::chrono::system_clock::time_point X509_Time::to_std_timepoint() const
254 {
255 return calendar_point(m_year, m_month, m_day, m_hour, m_minute, m_second).to_std_timepoint();
256 }
257
258 /*
259 * Compare two X509_Times for in various ways
260 */
261 bool operator==(const X509_Time& t1, const X509_Time& t2)
262 { return (t1.cmp(t2) == 0); }
263 bool operator!=(const X509_Time& t1, const X509_Time& t2)
264 { return (t1.cmp(t2) != 0); }
265
266 bool operator<=(const X509_Time& t1, const X509_Time& t2)
267 { return (t1.cmp(t2) <= 0); }
268 bool operator>=(const X509_Time& t1, const X509_Time& t2)
269 { return (t1.cmp(t2) >= 0); }
270
271 bool operator<(const X509_Time& t1, const X509_Time& t2)
272 { return (t1.cmp(t2) < 0); }
273 bool operator>(const X509_Time& t1, const X509_Time& t2)
274 { return (t1.cmp(t2) > 0); }
275
276 }
Botan::to_u32bit
uint32_t to_u32bit(const std::string &str)
Definition: parsing.cpp:18
Botan::calendar_point::to_std_timepoint
std::chrono::system_clock::time_point to_std_timepoint() const
Definition: calendar.cpp:117
Botan::operator>=
bool operator>=(const X509_Time &t1, const X509_Time &t2)
Definition: asn1_time.cpp:268
Botan::Invalid_Argument
Definition: exceptn.h:34
Botan::DER_Encoder::add_object
DER_Encoder & add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, const uint8_t rep[], size_t length)
Definition: der_enc.cpp:381
Botan::operator>
bool operator>(const X509_Time &t1, const X509_Time &t2)
Definition: asn1_time.cpp:273
Botan::UTC_OR_GENERALIZED_TIME
Definition: asn1_obj.h:52
Botan::X509_Time::cmp
int32_t cmp(const X509_Time &other) const
Compare this time against another.
Definition: asn1_time.cpp:120
Botan::calendar_point::year
uint32_t year
Definition: calendar.h:24
Botan::operator!=
bool operator!=(const AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
Definition: alg_id.cpp:82
Botan::calendar_point::day
uint32_t day
Definition: calendar.h:30
Botan::operator==
bool operator==(const AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
Definition: alg_id.cpp:67
std
Definition: bigint.h:619
Botan::Invalid_State
Definition: exceptn.h:61
Botan::X509_Time::decode_from
void decode_from(BER_Decoder &) override
Definition: asn1_time.cpp:50
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
Botan::calendar_point::hour
uint32_t hour
Definition: calendar.h:33
Botan::operator<
bool operator<(const OID &a, const OID &b)
Definition: asn1_oid.cpp:105
Botan::X509_Time::X509_Time
X509_Time()=default
Create an invalid X509_Time.
Botan::UNIVERSAL
Definition: asn1_obj.h:23
Botan::X509_Time::encode_into
void encode_into(DER_Encoder &) const override
DER encode a X509_Time.
Definition: asn1_time.cpp:39
BOTAN_ASSERT
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
Botan::X509_Time::to_std_timepoint
std::chrono::system_clock::time_point to_std_timepoint() const
Returns a STL timepoint object.
Definition: asn1_time.cpp:253
Botan::DER_Encoder
Definition: der_enc.h:22
Botan::Charset::transcode
std::string transcode(const std::string &str, Character_Set to, Character_Set from)
Definition: charset.cpp:103
Botan::ASN1_Tag
ASN1_Tag
Definition: asn1_obj.h:22
Botan::calendar_point
Definition: calendar.h:21
Botan::LATIN1_CHARSET
Definition: charset.h:23
Botan::X509_Time::time_is_set
bool time_is_set() const
Return if the time has been set somehow.
Definition: asn1_time.cpp:115
Botan
Definition: alg_id.cpp:13
Botan::BER_Decoder::get_next_object
BER_Object get_next_object()
Definition: ber_dec.cpp:210
Botan::UTC_TIME
Definition: asn1_obj.h:50
Botan::calendar_point::month
uint32_t month
Definition: calendar.h:27
Botan::X509_Time::to_string
std::string to_string() const
Return an internal string representation of the time.
Definition: asn1_time.cpp:60
Botan::LOCAL_CHARSET
Definition: charset.h:20
Botan::BER_Object::type_tag
ASN1_Tag type_tag
Definition: asn1_obj.h:91
Botan::GENERALIZED_TIME
Definition: asn1_obj.h:51
Botan::calendar_point::minutes
uint32_t minutes
Definition: calendar.h:36
Botan::X509_Time::readable_string
std::string readable_string() const
Returns a human friendly string replesentation of no particular formatting.
Definition: asn1_time.cpp:97
Botan::operator<=
bool operator<=(const X509_Time &t1, const X509_Time &t2)
Definition: asn1_time.cpp:266
Botan::calendar_point::seconds
uint32_t seconds
Definition: calendar.h:41
Botan::BER_Decoder
Definition: ber_dec.h:19
Botan::BER_Object
Definition: asn1_obj.h:85
Botan::Encoding_Error
Definition: exceptn.h:180
Botan::X509_Time
Definition: asn1_time.h:19
Botan::calendar_value
calendar_point calendar_value(const std::chrono::system_clock::time_point &time_point)
Definition: calendar.cpp:177