10#include <botan/internal/parsing.h>
12#include <botan/exceptn.h>
13#include <botan/internal/fmt.h>
14#include <botan/internal/loadstor.h>
24 if(x !=
static_cast<uint16_t
>(x)) {
28 return static_cast<uint16_t
>(x);
32 const std::string str(str_view);
35 for(
const char chr : str) {
36 if(chr <
'0' || chr >
'9') {
41 const unsigned long int x = std::stoul(str);
43 if constexpr(
sizeof(
unsigned long int) > 4) {
45 if(x > std::numeric_limits<uint32_t>::max()) {
50 return static_cast<uint32_t
>(x);
57 if(scan_name.find(
'(') == std::string::npos && scan_name.find(
')') == std::string::npos) {
58 return {std::string(scan_name)};
61 std::string name(scan_name);
62 std::string substring;
63 std::vector<std::string> elems;
66 elems.push_back(name.substr(0, name.find(
'(')));
67 name = name.substr(name.find(
'('));
69 for(
auto i = name.begin(); i != name.end(); ++i) {
76 if(level == 1 && i == name.end() - 1) {
77 if(elems.size() == 1) {
78 elems.push_back(substring.substr(1));
80 elems.push_back(substring);
85 if(level == 0 || (level == 1 && i != name.end() - 1)) {
91 if(c ==
',' && level == 1) {
92 if(elems.size() == 1) {
93 elems.push_back(substring.substr(1));
95 elems.push_back(substring);
103 if(!substring.empty()) {
110std::vector<std::string>
split_on(std::string_view str,
char delim) {
111 std::vector<std::string> elems;
117 for(
const char c : str) {
119 if(!substr.empty()) {
120 elems.push_back(substr);
131 elems.push_back(substr);
139std::string
string_join(
const std::vector<std::string>& strs,
char delim) {
140 std::ostringstream out;
142 for(
size_t i = 0; i != strs.size(); ++i) {
158 if(str.size() < 3 + 4 * 1 || str.size() > 3 + 4 * 3) {
169 size_t cur_digits = 0;
171 for(
const char c : str) {
174 if(cur_digits == 0) {
184 ip = (ip << 8) | accum;
186 }
else if(c >=
'0' && c <=
'9') {
187 const auto d =
static_cast<uint8_t
>(c -
'0');
190 if(cur_digits > 0 && accum == 0) {
193 accum = (accum * 10) + d;
207 if(cur_digits == 0) {
216 ip = (ip << 8) | accum;
228 std::array<uint16_t, 8> pre{};
229 std::array<uint16_t, 8> post{};
230 size_t pre_count = 0;
231 size_t post_count = 0;
232 bool seen_double_colon =
false;
234 auto hex_value = [](
char c) -> std::optional<uint8_t> {
235 if(c >=
'0' && c <=
'9') {
237 }
else if(c >=
'a' && c <=
'f') {
238 return 10 + (c -
'a');
239 }
else if(c >=
'A' && c <=
'F') {
240 return 10 + (c -
'A');
247 bool expect_group =
true;
249 while(idx < str.size()) {
250 if(str[idx] ==
':') {
251 if(idx + 1 < str.size() && str[idx + 1] ==
':') {
252 if(seen_double_colon) {
255 seen_double_colon =
true;
257 expect_group = (idx < str.size());
271 size_t hex_chars = 0;
272 while(idx < str.size() && hex_chars < 4) {
273 const auto digit = hex_value(str[idx]);
274 if(digit.has_value() ==
false) {
277 group = (group << 4) | static_cast<uint32_t>(digit.value());
285 if(hex_chars == 4 && idx < str.size() && hex_value(str[idx]).has_value()) {
289 if(seen_double_colon) {
290 if(post_count >= 8) {
293 post[post_count++] =
static_cast<uint16_t
>(group);
298 pre[pre_count++] =
static_cast<uint16_t
>(group);
300 expect_group =
false;
308 const size_t total_groups = pre_count + post_count;
309 if(seen_double_colon) {
311 if(total_groups > 7) {
315 if(total_groups != 8) {
320 std::array<uint8_t, 16> out{};
321 for(
size_t i = 0; i != pre_count; ++i) {
325 const size_t gap = 8 - total_groups;
326 for(
size_t i = 0; i != post_count; ++i) {
327 const size_t target = pre_count + gap + i;
335 static const char* hex =
"0123456789abcdef";
340 for(
size_t i = 0; i != 16; i += 2) {
344 const uint16_t group =
make_uint16(a[i], a[i + 1]);
345 bool started =
false;
347 for(
int s = 12; s >= 0; s -= 4) {
348 const auto nibble = (group >> s) & 0xF;
349 if(nibble != 0 || started || s == 0) {
350 out.push_back(hex[nibble]);
367 for(
size_t i = 0; i != 4; ++i) {
371 str += std::to_string(bits[i]);
380 std::string lower(str);
381 for(
char& c : lower) {
382 if(c >=
'A' && c <=
'Z') {
383 c =
static_cast<char>(c + (
'a' -
'A'));
390 if(host.empty() || issued.empty()) {
395 if(host.size() > 253) {
403 if(issued.size() > host.size() + 1) {
411 if(issued.find(
'\0') != std::string_view::npos) {
416 if(host.find(
'*') != std::string_view::npos) {
421 if(host.back() ==
'.') {
426 if(host.find(
"..") != std::string_view::npos) {
431 auto dns_char_eq = [](
char a,
char b) ->
bool {
435 const auto la =
static_cast<unsigned char>(a | 0x20);
436 const auto lb =
static_cast<unsigned char>(b | 0x20);
437 return la == lb && la >=
'a' && la <=
'z';
440 auto dns_char_eq_range = [&](std::string_view a, std::string_view b) ->
bool {
441 if(a.size() != b.size()) {
444 for(
size_t i = 0; i != a.size(); ++i) {
445 if(!dns_char_eq(a[i], b[i])) {
453 if(dns_char_eq_range(issued, host)) {
458 const size_t first_star = issued.find(
'*');
459 const bool has_wildcard = (first_star != std::string_view::npos);
462 if(has_wildcard && issued.find(
'*', first_star + 1) != std::string_view::npos) {
481 size_t dots_seen = 0;
484 for(
size_t i = 0; i != issued.size(); ++i) {
485 if(issued[i] ==
'.') {
489 if(issued[i] ==
'*') {
500 const size_t advance = (host.size() - issued.size() + 1);
502 if(host_idx + advance > host.size()) {
507 for(
size_t k = host_idx; k != host_idx + advance; ++k) {
515 if(!dns_char_eq(issued[i], host[host_idx])) {
532 if(name.size() > 255) {
540 if(name.starts_with(
".") || name.ends_with(
".")) {
549 constexpr uint8_t DNS_CHAR_MAPPING[128] = {
550 '\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
551 '\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
552 '\0',
'\0',
'\0',
'\0',
'*',
'\0',
'\0',
'-',
'.',
'\0',
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
553 '9',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'\0',
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
554 'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'\0',
'\0',
'\0',
'\0',
555 '\0',
'\0',
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
556 'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'\0',
'\0',
'\0',
'\0',
'\0',
561 canon.reserve(name.size());
564 size_t current_label_length = 0;
566 for(
size_t i = 0; i != name.size(); ++i) {
567 const char c = name[i];
570 if(i > 0 && name[i - 1] ==
'.') {
571 throw Decoding_Error(
"DNS name contains sequential period chars");
574 if(current_label_length == 0) {
577 current_label_length = 0;
579 current_label_length++;
581 if(current_label_length > 63) {
582 throw Decoding_Error(
"DNS name label exceeds maximum length of 63 characters");
586 const uint8_t cu =
static_cast<uint8_t
>(c);
588 throw Decoding_Error(
"DNS name must not contain any extended ASCII code points");
590 const uint8_t mapped = DNS_CHAR_MAPPING[cu];
596 if(i == 0 || (i > 0 && name[i - 1] ==
'.')) {
598 }
else if(i == name.size() - 1 || (i < name.size() - 1 && name[i + 1] ==
'.')) {
602 canon.push_back(
static_cast<char>(mapped));
605 if(current_label_length == 0) {
#define BOTAN_ASSERT_NOMSG(expr)
Decoding_Error(std::string_view name)
Invalid_Algorithm_Name(std::string_view name)
Invalid_Argument(std::string_view msg)
uint32_t to_u32bit(std::string_view str_view)
constexpr uint8_t get_byte(T input)
uint16_t to_uint16(std::string_view str)
std::string fmt(std::string_view format, const T &... args)
std::string tolower_string(std::string_view str)
std::vector< std::string > split_on(std::string_view str, char delim)
std::vector< std::string > parse_algorithm_name(std::string_view scan_name)
std::string check_and_canonicalize_dns_name(std::string_view name)
std::string string_join(const std::vector< std::string > &strs, char delim)
std::optional< std::array< uint8_t, 16 > > string_to_ipv6(std::string_view str)
std::optional< uint32_t > string_to_ipv4(std::string_view str)
std::string ipv4_to_string(uint32_t ip)
bool host_wildcard_match(std::string_view issued, std::string_view host)
constexpr auto store_be(ParamTs &&... params)
std::string ipv6_to_string(std::span< const uint8_t, 16 > a)
constexpr uint16_t make_uint16(uint8_t i0, uint8_t i1)