Botan 2.1.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

parsing.cpp
Go to the documentation of this file.
1 /*
2 * Various string utils and parsing functions
3 * (C) 1999-2007,2013,2014,2015 Jack Lloyd
4 * (C) 2015 Simon Warta (Kullo GmbH)
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8
9 #include <botan/parsing.h>
10 #include <botan/exceptn.h>
11 #include <botan/charset.h>
12 #include <botan/loadstor.h>
13 #include <limits>
14 #include <set>
15
16 namespace Botan {
17
18 uint32_t to_u32bit(const std::string& str)
19 {
20 try
21 {
22 // std::stoul is not strict enough. Ensure that str is digit only [0-9]*
23 for (const char chr : str)
24 {
25 if (chr < '0' || chr > '9')
26 {
27 auto chrAsString = std::string(1, chr);
28 throw Invalid_Argument("String contains non-digit char: " + chrAsString);
29 }
30 }
31
32 const auto integerValue = std::stoul(str);
33
34 // integerValue might be uint64
35 if (integerValue > std::numeric_limits<uint32_t>::max())
36 {
37 throw Invalid_Argument("Integer value exceeds 32 bit range: " + std::to_string(integerValue));
38 }
39
40 return integerValue;
41 }
42 catch(std::exception& e)
43 {
44 auto message = std::string("Could not read '" + str + "' as decimal string");
45 auto exceptionMessage = std::string(e.what());
46 if (!exceptionMessage.empty()) message += ": " + exceptionMessage;
47 throw Exception(message);
48 }
49 }
50
51 /*
52 * Convert a string into a time duration
53 */
54 uint32_t timespec_to_u32bit(const std::string& timespec)
55 {
56 if(timespec.empty())
57 return 0;
58
59 const char suffix = timespec[timespec.size()-1];
60 std::string value = timespec.substr(0, timespec.size()-1);
61
62 uint32_t scale = 1;
63
64 if(Charset::is_digit(suffix))
65 value += suffix;
66 else if(suffix == 's')
67 scale = 1;
68 else if(suffix == 'm')
69 scale = 60;
70 else if(suffix == 'h')
71 scale = 60 * 60;
72 else if(suffix == 'd')
73 scale = 24 * 60 * 60;
74 else if(suffix == 'y')
75 scale = 365 * 24 * 60 * 60;
76 else
77 throw Decoding_Error("timespec_to_u32bit: Bad input " + timespec);
78
79 return scale * to_u32bit(value);
80 }
81
82 /*
83 * Parse a SCAN-style algorithm name
84 */
85 std::vector<std::string> parse_algorithm_name(const std::string& namex)
86 {
87 if(namex.find('(') == std::string::npos &&
88 namex.find(')') == std::string::npos)
89 return std::vector<std::string>(1, namex);
90
91 std::string name = namex, substring;
92 std::vector<std::string> elems;
93 size_t level = 0;
94
95 elems.push_back(name.substr(0, name.find('(')));
96 name = name.substr(name.find('('));
97
98 for(auto i = name.begin(); i != name.end(); ++i)
99 {
100 char c = *i;
101
102 if(c == '(')
103 ++level;
104 if(c == ')')
105 {
106 if(level == 1 && i == name.end() - 1)
107 {
108 if(elems.size() == 1)
109 elems.push_back(substring.substr(1));
110 else
111 elems.push_back(substring);
112 return elems;
113 }
114
115 if(level == 0 || (level == 1 && i != name.end() - 1))
116 throw Invalid_Algorithm_Name(namex);
117 --level;
118 }
119
120 if(c == ',' && level == 1)
121 {
122 if(elems.size() == 1)
123 elems.push_back(substring.substr(1));
124 else
125 elems.push_back(substring);
126 substring.clear();
127 }
128 else
129 substring += c;
130 }
131
132 if(!substring.empty())
133 throw Invalid_Algorithm_Name(namex);
134
135 return elems;
136 }
137
138 std::vector<std::string> split_on(const std::string& str, char delim)
139 {
140 return split_on_pred(str, [delim](char c) { return c == delim; });
141 }
142
143 std::vector<std::string> split_on_pred(const std::string& str,
144 std::function<bool (char)> pred)
145 {
146 std::vector<std::string> elems;
147 if(str.empty()) return elems;
148
149 std::string substr;
150 for(auto i = str.begin(); i != str.end(); ++i)
151 {
152 if(pred(*i))
153 {
154 if(!substr.empty())
155 elems.push_back(substr);
156 substr.clear();
157 }
158 else
159 substr += *i;
160 }
161
162 if(substr.empty())
163 throw Invalid_Argument("Unable to split string: " + str);
164 elems.push_back(substr);
165
166 return elems;
167 }
168
169 /*
170 * Join a string
171 */
172 std::string string_join(const std::vector<std::string>& strs, char delim)
173 {
174 std::string out = "";
175
176 for(size_t i = 0; i != strs.size(); ++i)
177 {
178 if(i != 0)
179 out += delim;
180 out += strs[i];
181 }
182
183 return out;
184 }
185
186 /*
187 * Parse an ASN.1 OID string
188 */
189 std::vector<uint32_t> parse_asn1_oid(const std::string& oid)
190 {
191 std::string substring;
192 std::vector<uint32_t> oid_elems;
193
194 for(auto i = oid.begin(); i != oid.end(); ++i)
195 {
196 char c = *i;
197
198 if(c == '.')
199 {
200 if(substring.empty())
201 throw Invalid_OID(oid);
202 oid_elems.push_back(to_u32bit(substring));
203 substring.clear();
204 }
205 else
206 substring += c;
207 }
208
209 if(substring.empty())
210 throw Invalid_OID(oid);
211 oid_elems.push_back(to_u32bit(substring));
212
213 if(oid_elems.size() < 2)
214 throw Invalid_OID(oid);
215
216 return oid_elems;
217 }
218
219 /*
220 * X.500 String Comparison
221 */
222 bool x500_name_cmp(const std::string& name1, const std::string& name2)
223 {
224 auto p1 = name1.begin();
225 auto p2 = name2.begin();
226
227 while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1;
228 while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2;
229
230 while(p1 != name1.end() && p2 != name2.end())
231 {
232 if(Charset::is_space(*p1))
233 {
234 if(!Charset::is_space(*p2))
235 return false;
236
237 while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1;
238 while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2;
239
240 if(p1 == name1.end() && p2 == name2.end())
241 return true;
242 if(p1 == name1.end() || p2 == name2.end())
243 return false;
244 }
245
246 if(!Charset::caseless_cmp(*p1, *p2))
247 return false;
248 ++p1;
249 ++p2;
250 }
251
252 while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1;
253 while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2;
254
255 if((p1 != name1.end()) || (p2 != name2.end()))
256 return false;
257 return true;
258 }
259
260 /*
261 * Convert a decimal-dotted string to binary IP
262 */
263 uint32_t string_to_ipv4(const std::string& str)
264 {
265 std::vector<std::string> parts = split_on(str, '.');
266
267 if(parts.size() != 4)
268 throw Decoding_Error("Invalid IP string " + str);
269
270 uint32_t ip = 0;
271
272 for(auto part = parts.begin(); part != parts.end(); ++part)
273 {
274 uint32_t octet = to_u32bit(*part);
275
276 if(octet > 255)
277 throw Decoding_Error("Invalid IP string " + str);
278
279 ip = (ip << 8) | (octet & 0xFF);
280 }
281
282 return ip;
283 }
284
285 /*
286 * Convert an IP address to decimal-dotted string
287 */
288 std::string ipv4_to_string(uint32_t ip)
289 {
290 std::string str;
291
292 for(size_t i = 0; i != sizeof(ip); ++i)
293 {
294 if(i)
295 str += ".";
296 str += std::to_string(get_byte(i, ip));
297 }
298
299 return str;
300 }
301
302 std::string erase_chars(const std::string& str, const std::set<char>& chars)
303 {
304 std::string out;
305
306 for(auto c: str)
307 if(chars.count(c) == 0)
308 out += c;
309
310 return out;
311 }
312
313 std::string replace_chars(const std::string& str,
314 const std::set<char>& chars,
315 char to_char)
316 {
317 std::string out = str;
318
319 for(size_t i = 0; i != out.size(); ++i)
320 if(chars.count(out[i]))
321 out[i] = to_char;
322
323 return out;
324 }
325
326 std::string replace_char(const std::string& str, char from_char, char to_char)
327 {
328 std::string out = str;
329
330 for(size_t i = 0; i != out.size(); ++i)
331 if(out[i] == from_char)
332 out[i] = to_char;
333
334 return out;
335 }
336
337 bool host_wildcard_match(const std::string& issued, const std::string& host)
338 {
339 if(issued == host)
340 return true;
341
342 if(issued.size() > 2 && issued[0] == '*' && issued[1] == '.')
343 {
344 size_t host_i = host.find('.');
345 if(host_i == std::string::npos || host_i == host.size() - 1)
346 return false;
347
348 const std::string host_base = host.substr(host_i + 1);
349 const std::string issued_base = issued.substr(2);
350
351 if(host_base == issued_base)
352 return true;
353 }
354
355 return false;
356 }
357
358 }
Botan::parse_algorithm_name
std::vector< std::string > parse_algorithm_name(const std::string &namex)
Definition: parsing.cpp:85
Botan::to_u32bit
uint32_t to_u32bit(const std::string &str)
Definition: parsing.cpp:18
Botan::Invalid_Argument
Definition: exceptn.h:34
Botan::x500_name_cmp
bool x500_name_cmp(const std::string &name1, const std::string &name2)
Definition: parsing.cpp:222
Botan::string_join
std::string string_join(const std::vector< std::string > &strs, char delim)
Definition: parsing.cpp:172
Botan::Exception
Definition: exceptn.h:21
Botan::Charset::caseless_cmp
bool caseless_cmp(char a, char b)
Definition: charset.cpp:193
Botan::replace_chars
std::string replace_chars(const std::string &str, const std::set< char > &chars, char to_char)
Definition: parsing.cpp:313
Botan::erase_chars
std::string erase_chars(const std::string &str, const std::set< char > &chars)
Definition: parsing.cpp:302
Botan::split_on
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:138
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
Botan::ipv4_to_string
std::string ipv4_to_string(uint32_t ip)
Definition: parsing.cpp:288
Botan::split_on_pred
std::vector< std::string > split_on_pred(const std::string &str, std::function< bool(char)> pred)
Definition: parsing.cpp:143
Botan::Decoding_Error
Definition: exceptn.h:189
Botan
Definition: alg_id.cpp:13
Botan::CT::max
T max(T a, T b)
Definition: ct_utils.h:173
Botan::Charset::is_digit
bool is_digit(char c)
Definition: charset.cpp:128
Botan::Charset::is_space
bool is_space(char c)
Definition: charset.cpp:139
Botan::Invalid_Algorithm_Name
Definition: exceptn.h:170
Botan::parse_asn1_oid
std::vector< uint32_t > parse_asn1_oid(const std::string &oid)
Definition: parsing.cpp:189
Botan::get_byte
uint8_t get_byte(size_t byte_num, T input)
Definition: loadstor.h:47
Botan::host_wildcard_match
bool host_wildcard_match(const std::string &issued, const std::string &host)
Definition: parsing.cpp:337
Botan::timespec_to_u32bit
uint32_t timespec_to_u32bit(const std::string &timespec)
Definition: parsing.cpp:54
Botan::string_to_ipv4
uint32_t string_to_ipv4(const std::string &str)
Definition: parsing.cpp:263
Botan::replace_char
std::string replace_char(const std::string &str, char from_char, char to_char)
Definition: parsing.cpp:326
Botan::Invalid_OID
Definition: exceptn.h:207