Botan  2.1.0
Crypto and TLS for C++11
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 }
std::vector< std::string > parse_algorithm_name(const std::string &namex)
Definition: parsing.cpp:85
uint32_t to_u32bit(const std::string &str)
Definition: parsing.cpp:18
bool x500_name_cmp(const std::string &name1, const std::string &name2)
Definition: parsing.cpp:222
std::string string_join(const std::vector< std::string > &strs, char delim)
Definition: parsing.cpp:172
bool caseless_cmp(char a, char b)
Definition: charset.cpp:193
std::string replace_chars(const std::string &str, const std::set< char > &chars, char to_char)
Definition: parsing.cpp:313
std::string erase_chars(const std::string &str, const std::set< char > &chars)
Definition: parsing.cpp:302
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:138
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
std::string ipv4_to_string(uint32_t ip)
Definition: parsing.cpp:288
std::vector< std::string > split_on_pred(const std::string &str, std::function< bool(char)> pred)
Definition: parsing.cpp:143
Definition: alg_id.cpp:13
T max(T a, T b)
Definition: ct_utils.h:173
bool is_digit(char c)
Definition: charset.cpp:128
bool is_space(char c)
Definition: charset.cpp:139
std::vector< uint32_t > parse_asn1_oid(const std::string &oid)
Definition: parsing.cpp:189
uint8_t get_byte(size_t byte_num, T input)
Definition: loadstor.h:47
bool host_wildcard_match(const std::string &issued, const std::string &host)
Definition: parsing.cpp:337
uint32_t timespec_to_u32bit(const std::string &timespec)
Definition: parsing.cpp:54
uint32_t string_to_ipv4(const std::string &str)
Definition: parsing.cpp:263
std::string replace_char(const std::string &str, char from_char, char to_char)
Definition: parsing.cpp:326