1 /* 2 * parseutil.c - parse utilities for string and wire conversion 3 * 4 * (c) NLnet Labs, 2004-2006 5 * 6 * See the file LICENSE for the license 7 */ 8 /** 9 * \file 10 * 11 * Utility functions for parsing, base32(DNS variant) and base64 encoding 12 * and decoding, Hex, Time units, Escape codes. 13 */ 14 15 #include "config.h" 16 #include "sldns/parseutil.h" 17 #include <sys/time.h> 18 #include <time.h> 19 #include <ctype.h> 20 21 sldns_lookup_table * 22 sldns_lookup_by_name(sldns_lookup_table *table, const char *name) 23 { 24 while (table->name != NULL) { 25 if (strcasecmp(name, table->name) == 0) 26 return table; 27 table++; 28 } 29 return NULL; 30 } 31 32 sldns_lookup_table * 33 sldns_lookup_by_id(sldns_lookup_table *table, int id) 34 { 35 while (table->name != NULL) { 36 if (table->id == id) 37 return table; 38 table++; 39 } 40 return NULL; 41 } 42 43 /* Number of days per month (except for February in leap years). */ 44 static const int mdays[] = { 45 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 46 }; 47 48 #define LDNS_MOD(x,y) (((x) % (y) < 0) ? ((x) % (y) + (y)) : ((x) % (y))) 49 #define LDNS_DIV(x,y) (((x) % (y) < 0) ? ((x) / (y) - 1 ) : ((x) / (y))) 50 51 static int 52 is_leap_year(int year) 53 { 54 return LDNS_MOD(year, 4) == 0 && (LDNS_MOD(year, 100) != 0 55 || LDNS_MOD(year, 400) == 0); 56 } 57 58 static int 59 leap_days(int y1, int y2) 60 { 61 --y1; 62 --y2; 63 return (LDNS_DIV(y2, 4) - LDNS_DIV(y1, 4)) - 64 (LDNS_DIV(y2, 100) - LDNS_DIV(y1, 100)) + 65 (LDNS_DIV(y2, 400) - LDNS_DIV(y1, 400)); 66 } 67 68 /* 69 * Code adapted from Python 2.4.1 sources (Lib/calendar.py). 70 */ 71 time_t 72 sldns_mktime_from_utc(const struct tm *tm) 73 { 74 int year = 1900 + tm->tm_year; 75 time_t days = 365 * ((time_t) year - 1970) + leap_days(1970, year); 76 time_t hours; 77 time_t minutes; 78 time_t seconds; 79 int i; 80 81 for (i = 0; i < tm->tm_mon; ++i) { 82 days += mdays[i]; 83 } 84 if (tm->tm_mon > 1 && is_leap_year(year)) { 85 ++days; 86 } 87 days += tm->tm_mday - 1; 88 89 hours = days * 24 + tm->tm_hour; 90 minutes = hours * 60 + tm->tm_min; 91 seconds = minutes * 60 + tm->tm_sec; 92 93 return seconds; 94 } 95 96 #if SIZEOF_TIME_T <= 4 97 98 static void 99 sldns_year_and_yday_from_days_since_epoch(int64_t days, struct tm *result) 100 { 101 int year = 1970; 102 int new_year; 103 104 while (days < 0 || days >= (int64_t) (is_leap_year(year) ? 366 : 365)) { 105 new_year = year + (int) LDNS_DIV(days, 365); 106 days -= (new_year - year) * 365; 107 days -= leap_days(year, new_year); 108 year = new_year; 109 } 110 result->tm_year = year; 111 result->tm_yday = (int) days; 112 } 113 114 /* Number of days per month in a leap year. */ 115 static const int leap_year_mdays[] = { 116 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 117 }; 118 119 static void 120 sldns_mon_and_mday_from_year_and_yday(struct tm *result) 121 { 122 int idays = result->tm_yday; 123 const int *mon_lengths = is_leap_year(result->tm_year) ? 124 leap_year_mdays : mdays; 125 126 result->tm_mon = 0; 127 while (idays >= mon_lengths[result->tm_mon]) { 128 idays -= mon_lengths[result->tm_mon++]; 129 } 130 result->tm_mday = idays + 1; 131 } 132 133 static void 134 sldns_wday_from_year_and_yday(struct tm *result) 135 { 136 result->tm_wday = 4 /* 1-1-1970 was a thursday */ 137 + LDNS_MOD((result->tm_year - 1970), 7) * LDNS_MOD(365, 7) 138 + leap_days(1970, result->tm_year) 139 + result->tm_yday; 140 result->tm_wday = LDNS_MOD(result->tm_wday, 7); 141 if (result->tm_wday < 0) { 142 result->tm_wday += 7; 143 } 144 } 145 146 static struct tm * 147 sldns_gmtime64_r(int64_t clock, struct tm *result) 148 { 149 result->tm_isdst = 0; 150 result->tm_sec = (int) LDNS_MOD(clock, 60); 151 clock = LDNS_DIV(clock, 60); 152 result->tm_min = (int) LDNS_MOD(clock, 60); 153 clock = LDNS_DIV(clock, 60); 154 result->tm_hour = (int) LDNS_MOD(clock, 24); 155 clock = LDNS_DIV(clock, 24); 156 157 sldns_year_and_yday_from_days_since_epoch(clock, result); 158 sldns_mon_and_mday_from_year_and_yday(result); 159 sldns_wday_from_year_and_yday(result); 160 result->tm_year -= 1900; 161 162 return result; 163 } 164 165 #endif /* SIZEOF_TIME_T <= 4 */ 166 167 static int64_t 168 sldns_serial_arithmetics_time(int32_t time, time_t now) 169 { 170 int32_t offset = (int32_t)((uint32_t) time - (uint32_t) now); 171 return (int64_t) now + offset; 172 } 173 174 struct tm * 175 sldns_serial_arithmetics_gmtime_r(int32_t time, time_t now, struct tm *result) 176 { 177 #if SIZEOF_TIME_T <= 4 178 int64_t secs_since_epoch = sldns_serial_arithmetics_time(time, now); 179 return sldns_gmtime64_r(secs_since_epoch, result); 180 #else 181 time_t secs_since_epoch = sldns_serial_arithmetics_time(time, now); 182 return gmtime_r(&secs_since_epoch, result); 183 #endif 184 } 185 186 int 187 sldns_hexdigit_to_int(char ch) 188 { 189 switch (ch) { 190 case '0': return 0; 191 case '1': return 1; 192 case '2': return 2; 193 case '3': return 3; 194 case '4': return 4; 195 case '5': return 5; 196 case '6': return 6; 197 case '7': return 7; 198 case '8': return 8; 199 case '9': return 9; 200 case 'a': case 'A': return 10; 201 case 'b': case 'B': return 11; 202 case 'c': case 'C': return 12; 203 case 'd': case 'D': return 13; 204 case 'e': case 'E': return 14; 205 case 'f': case 'F': return 15; 206 default: 207 return -1; 208 } 209 } 210 211 uint32_t 212 sldns_str2period(const char *nptr, const char **endptr, int* overflow) 213 { 214 int sign = 0; 215 uint32_t i = 0; 216 uint32_t seconds = 0; 217 const uint32_t maxint = 0xffffffff; 218 *overflow = 0; 219 220 for(*endptr = nptr; **endptr; (*endptr)++) { 221 switch (**endptr) { 222 case ' ': 223 case '\t': 224 break; 225 case '-': 226 if(sign == 0) { 227 sign = -1; 228 } else { 229 return seconds; 230 } 231 break; 232 case '+': 233 if(sign == 0) { 234 sign = 1; 235 } else { 236 return seconds; 237 } 238 break; 239 case 's': 240 case 'S': 241 if(seconds > maxint-i) { 242 *overflow = 1; 243 return 0; 244 } 245 seconds += i; 246 i = 0; 247 break; 248 case 'm': 249 case 'M': 250 if(i > maxint/60 || seconds > maxint-(i*60)) { 251 *overflow = 1; 252 return 0; 253 } 254 seconds += i * 60; 255 i = 0; 256 break; 257 case 'h': 258 case 'H': 259 if(i > maxint/(60*60) || seconds > maxint-(i*60*60)) { 260 *overflow = 1; 261 return 0; 262 } 263 seconds += i * 60 * 60; 264 i = 0; 265 break; 266 case 'd': 267 case 'D': 268 if(i > maxint/(60*60*24) || seconds > maxint-(i*60*60*24)) { 269 *overflow = 1; 270 return 0; 271 } 272 seconds += i * 60 * 60 * 24; 273 i = 0; 274 break; 275 case 'w': 276 case 'W': 277 if(i > maxint/(60*60*24*7) || seconds > maxint-(i*60*60*24*7)) { 278 *overflow = 1; 279 return 0; 280 } 281 seconds += i * 60 * 60 * 24 * 7; 282 i = 0; 283 break; 284 case '0': 285 case '1': 286 case '2': 287 case '3': 288 case '4': 289 case '5': 290 case '6': 291 case '7': 292 case '8': 293 case '9': 294 if(i > maxint/10 || i*10 > maxint - (**endptr - '0')) { 295 *overflow = 1; 296 return 0; 297 } 298 i *= 10; 299 i += (**endptr - '0'); 300 break; 301 default: 302 if(seconds > maxint-i) { 303 *overflow = 1; 304 return 0; 305 } 306 seconds += i; 307 /* disregard signedness */ 308 return seconds; 309 } 310 } 311 if(seconds > maxint-i) { 312 *overflow = 1; 313 return 0; 314 } 315 seconds += i; 316 /* disregard signedness */ 317 return seconds; 318 } 319 320 int 321 sldns_parse_escape(uint8_t *ch_p, const char** str_p) 322 { 323 uint16_t val; 324 325 if ((*str_p)[0] && isdigit((unsigned char)(*str_p)[0]) && 326 (*str_p)[1] && isdigit((unsigned char)(*str_p)[1]) && 327 (*str_p)[2] && isdigit((unsigned char)(*str_p)[2])) { 328 329 val = (uint16_t)(((*str_p)[0] - '0') * 100 + 330 ((*str_p)[1] - '0') * 10 + 331 ((*str_p)[2] - '0')); 332 333 if (val > 255) { 334 goto error; 335 } 336 *ch_p = (uint8_t)val; 337 *str_p += 3; 338 return 1; 339 340 } else if ((*str_p)[0] && !isdigit((unsigned char)(*str_p)[0])) { 341 342 *ch_p = (uint8_t)*(*str_p)++; 343 return 1; 344 } 345 error: 346 *str_p = NULL; 347 return 0; /* LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE */ 348 } 349 350 /** parse one character, with escape codes */ 351 int 352 sldns_parse_char(uint8_t *ch_p, const char** str_p) 353 { 354 switch (**str_p) { 355 356 case '\0': return 0; 357 358 case '\\': *str_p += 1; 359 return sldns_parse_escape(ch_p, str_p); 360 361 default: *ch_p = (uint8_t)*(*str_p)++; 362 return 1; 363 } 364 } 365 366 size_t sldns_b32_ntop_calculate_size(size_t src_data_length) 367 { 368 return src_data_length == 0 ? 0 : ((src_data_length - 1) / 5 + 1) * 8; 369 } 370 371 size_t sldns_b32_ntop_calculate_size_no_padding(size_t src_data_length) 372 { 373 return ((src_data_length + 3) * 8 / 5) - 4; 374 } 375 376 static int 377 sldns_b32_ntop_base(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz, 378 int extended_hex, int add_padding) 379 { 380 size_t ret_sz; 381 const char* b32 = extended_hex ? "0123456789abcdefghijklmnopqrstuv" 382 : "abcdefghijklmnopqrstuvwxyz234567"; 383 384 size_t c = 0; /* c is used to carry partial base32 character over 385 * byte boundaries for sizes with a remainder. 386 * (i.e. src_sz % 5 != 0) 387 */ 388 389 ret_sz = add_padding ? sldns_b32_ntop_calculate_size(src_sz) 390 : sldns_b32_ntop_calculate_size_no_padding(src_sz); 391 392 /* Do we have enough space? */ 393 if (dst_sz < ret_sz + 1) 394 return -1; 395 396 /* We know the size; terminate the string */ 397 dst[ret_sz] = '\0'; 398 399 /* First process all chunks of five */ 400 while (src_sz >= 5) { 401 /* 00000... ........ ........ ........ ........ */ 402 dst[0] = b32[(src[0] ) >> 3]; 403 404 /* .....111 11...... ........ ........ ........ */ 405 dst[1] = b32[(src[0] & 0x07) << 2 | src[1] >> 6]; 406 407 /* ........ ..22222. ........ ........ ........ */ 408 dst[2] = b32[(src[1] & 0x3e) >> 1]; 409 410 /* ........ .......3 3333.... ........ ........ */ 411 dst[3] = b32[(src[1] & 0x01) << 4 | src[2] >> 4]; 412 413 /* ........ ........ ....4444 4....... ........ */ 414 dst[4] = b32[(src[2] & 0x0f) << 1 | src[3] >> 7]; 415 416 /* ........ ........ ........ .55555.. ........ */ 417 dst[5] = b32[(src[3] & 0x7c) >> 2]; 418 419 /* ........ ........ ........ ......66 666..... */ 420 dst[6] = b32[(src[3] & 0x03) << 3 | src[4] >> 5]; 421 422 /* ........ ........ ........ ........ ...77777 */ 423 dst[7] = b32[(src[4] & 0x1f) ]; 424 425 src_sz -= 5; 426 src += 5; 427 dst += 8; 428 } 429 /* Process what remains */ 430 switch (src_sz) { 431 case 4: /* ........ ........ ........ ......66 666..... */ 432 dst[6] = b32[(src[3] & 0x03) << 3]; 433 434 /* ........ ........ ........ .55555.. ........ */ 435 dst[5] = b32[(src[3] & 0x7c) >> 2]; 436 437 /* ........ ........ ....4444 4....... ........ */ 438 c = src[3] >> 7 ; 439 /* fallthrough */ 440 case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c]; 441 442 /* ........ .......3 3333.... ........ ........ */ 443 c = src[2] >> 4 ; 444 /* fallthrough */ 445 case 2: dst[3] = b32[(src[1] & 0x01) << 4 | c]; 446 447 /* ........ ..22222. ........ ........ ........ */ 448 dst[2] = b32[(src[1] & 0x3e) >> 1]; 449 450 /* .....111 11...... ........ ........ ........ */ 451 c = src[1] >> 6 ; 452 /* fallthrough */ 453 case 1: dst[1] = b32[(src[0] & 0x07) << 2 | c]; 454 455 /* 00000... ........ ........ ........ ........ */ 456 dst[0] = b32[ src[0] >> 3]; 457 } 458 /* Add padding */ 459 if (add_padding) { 460 switch (src_sz) { 461 case 1: dst[2] = '='; 462 dst[3] = '='; 463 /* fallthrough */ 464 case 2: dst[4] = '='; 465 /* fallthrough */ 466 case 3: dst[5] = '='; 467 dst[6] = '='; 468 /* fallthrough */ 469 case 4: dst[7] = '='; 470 } 471 } 472 return (int)ret_sz; 473 } 474 475 int 476 sldns_b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) 477 { 478 return sldns_b32_ntop_base(src, src_sz, dst, dst_sz, 0, 1); 479 } 480 481 int 482 sldns_b32_ntop_extended_hex(const uint8_t* src, size_t src_sz, 483 char* dst, size_t dst_sz) 484 { 485 return sldns_b32_ntop_base(src, src_sz, dst, dst_sz, 1, 1); 486 } 487 488 size_t sldns_b32_pton_calculate_size(size_t src_text_length) 489 { 490 return src_text_length * 5 / 8; 491 } 492 493 static int 494 sldns_b32_pton_base(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz, 495 int extended_hex, int check_padding) 496 { 497 size_t i = 0; 498 char ch = '\0'; 499 uint8_t buf[8]; 500 uint8_t* start = dst; 501 502 while (src_sz) { 503 /* Collect 8 characters in buf (if possible) */ 504 for (i = 0; i < 8; i++) { 505 506 do { 507 ch = *src++; 508 --src_sz; 509 510 } while (isspace((unsigned char)ch) && src_sz > 0); 511 512 if (ch == '=' || ch == '\0') 513 break; 514 515 else if (extended_hex) 516 517 if (ch >= '0' && ch <= '9') 518 buf[i] = (uint8_t)ch - '0'; 519 else if (ch >= 'a' && ch <= 'v') 520 buf[i] = (uint8_t)ch - 'a' + 10; 521 else if (ch >= 'A' && ch <= 'V') 522 buf[i] = (uint8_t)ch - 'A' + 10; 523 else 524 return -1; 525 526 else if (ch >= 'a' && ch <= 'z') 527 buf[i] = (uint8_t)ch - 'a'; 528 else if (ch >= 'A' && ch <= 'Z') 529 buf[i] = (uint8_t)ch - 'A'; 530 else if (ch >= '2' && ch <= '7') 531 buf[i] = (uint8_t)ch - '2' + 26; 532 else 533 return -1; 534 } 535 /* Less that 8 characters. We're done. */ 536 if (i < 8) 537 break; 538 539 /* Enough space available at the destination? */ 540 if (dst_sz < 5) 541 return -1; 542 543 /* 00000... ........ ........ ........ ........ */ 544 /* .....111 11...... ........ ........ ........ */ 545 dst[0] = buf[0] << 3 | buf[1] >> 2; 546 547 /* .....111 11...... ........ ........ ........ */ 548 /* ........ ..22222. ........ ........ ........ */ 549 /* ........ .......3 3333.... ........ ........ */ 550 dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; 551 552 /* ........ .......3 3333.... ........ ........ */ 553 /* ........ ........ ....4444 4....... ........ */ 554 dst[2] = buf[3] << 4 | buf[4] >> 1; 555 556 /* ........ ........ ....4444 4....... ........ */ 557 /* ........ ........ ........ .55555.. ........ */ 558 /* ........ ........ ........ ......66 666..... */ 559 dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; 560 561 /* ........ ........ ........ ......66 666..... */ 562 /* ........ ........ ........ ........ ...77777 */ 563 dst[4] = buf[6] << 5 | buf[7]; 564 565 dst += 5; 566 dst_sz -= 5; 567 } 568 /* Not ending on a eight byte boundary? */ 569 if (i > 0 && i < 8) { 570 571 /* Enough space available at the destination? */ 572 if (dst_sz < (i + 1) / 2) 573 return -1; 574 575 switch (i) { 576 case 7: /* ........ ........ ........ ......66 666..... */ 577 /* ........ ........ ........ .55555.. ........ */ 578 /* ........ ........ ....4444 4....... ........ */ 579 dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; 580 /* fallthrough */ 581 582 case 5: /* ........ ........ ....4444 4....... ........ */ 583 /* ........ .......3 3333.... ........ ........ */ 584 dst[2] = buf[3] << 4 | buf[4] >> 1; 585 /* fallthrough */ 586 587 case 4: /* ........ .......3 3333.... ........ ........ */ 588 /* ........ ..22222. ........ ........ ........ */ 589 /* .....111 11...... ........ ........ ........ */ 590 dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; 591 /* fallthrough */ 592 593 case 2: /* .....111 11...... ........ ........ ........ */ 594 /* 00000... ........ ........ ........ ........ */ 595 dst[0] = buf[0] << 3 | buf[1] >> 2; 596 597 break; 598 599 default: 600 return -1; 601 } 602 dst += (i + 1) / 2; 603 604 if (check_padding) { 605 /* Check remaining padding characters */ 606 if (ch != '=') 607 return -1; 608 609 /* One down, 8 - i - 1 more to come... */ 610 for (i = 8 - i - 1; i > 0; i--) { 611 612 do { 613 if (src_sz == 0) 614 return -1; 615 ch = *src++; 616 src_sz--; 617 618 } while (isspace((unsigned char)ch)); 619 620 if (ch != '=') 621 return -1; 622 } 623 } 624 } 625 return dst - start; 626 } 627 628 int 629 sldns_b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) 630 { 631 return sldns_b32_pton_base(src, src_sz, dst, dst_sz, 0, 1); 632 } 633 634 int 635 sldns_b32_pton_extended_hex(const char* src, size_t src_sz, 636 uint8_t* dst, size_t dst_sz) 637 { 638 return sldns_b32_pton_base(src, src_sz, dst, dst_sz, 1, 1); 639 } 640 641 size_t sldns_b64_ntop_calculate_size(size_t srcsize) 642 { 643 return ((((srcsize + 2) / 3) * 4) + 1); 644 } 645 646 /* RFC 1521, section 5.2. 647 * 648 * The encoding process represents 24-bit groups of input bits as output 649 * strings of 4 encoded characters. Proceeding from left to right, a 650 * 24-bit input group is formed by concatenating 3 8-bit input groups. 651 * These 24 bits are then treated as 4 concatenated 6-bit groups, each 652 * of which is translated into a single digit in the base64 alphabet. 653 * 654 * This routine does not insert spaces or linebreaks after 76 characters. 655 */ 656 static int sldns_b64_ntop_base(uint8_t const *src, size_t srclength, 657 char *target, size_t targsize, int base64url, int padding) 658 { 659 char* b64; 660 const char pad64 = '='; 661 size_t i = 0, o = 0; 662 if(base64url) 663 b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123" 664 "456789-_"; 665 else 666 b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123" 667 "456789+/"; 668 if(targsize < sldns_b64_ntop_calculate_size(srclength)) 669 return -1; 670 /* whole chunks: xxxxxxyy yyyyzzzz zzwwwwww */ 671 while(i+3 <= srclength) { 672 if(o+4 > targsize) return -1; 673 target[o] = b64[src[i] >> 2]; 674 target[o+1] = b64[ ((src[i]&0x03)<<4) | (src[i+1]>>4) ]; 675 target[o+2] = b64[ ((src[i+1]&0x0f)<<2) | (src[i+2]>>6) ]; 676 target[o+3] = b64[ (src[i+2]&0x3f) ]; 677 i += 3; 678 o += 4; 679 } 680 /* remainder */ 681 switch(srclength - i) { 682 case 2: 683 /* two at end, converted into A B C = */ 684 target[o] = b64[src[i] >> 2]; 685 target[o+1] = b64[ ((src[i]&0x03)<<4) | (src[i+1]>>4) ]; 686 target[o+2] = b64[ ((src[i+1]&0x0f)<<2) ]; 687 if(padding) { 688 target[o+3] = pad64; 689 /* i += 2; */ 690 o += 4; 691 } else { 692 o += 3; 693 } 694 break; 695 case 1: 696 /* one at end, converted into A B = = */ 697 target[o] = b64[src[i] >> 2]; 698 target[o+1] = b64[ ((src[i]&0x03)<<4) ]; 699 if(padding) { 700 target[o+2] = pad64; 701 target[o+3] = pad64; 702 /* i += 1; */ 703 o += 4; 704 } else { 705 o += 2; 706 } 707 break; 708 case 0: 709 default: 710 /* nothing */ 711 break; 712 } 713 /* assert: i == srclength */ 714 if(o+1 > targsize) return -1; 715 target[o] = 0; 716 return (int)o; 717 } 718 719 int sldns_b64_ntop(uint8_t const *src, size_t srclength, char *target, 720 size_t targsize) 721 { 722 return sldns_b64_ntop_base(src, srclength, target, targsize, 723 0 /* no base64url */, 1 /* padding */); 724 } 725 726 int sldns_b64url_ntop(uint8_t const *src, size_t srclength, char *target, 727 size_t targsize) 728 { 729 return sldns_b64_ntop_base(src, srclength, target, targsize, 730 1 /* base64url */, 0 /* no padding */); 731 } 732 733 size_t sldns_b64_pton_calculate_size(size_t srcsize) 734 { 735 return (((((srcsize + 3) / 4) * 3)) + 1); 736 } 737 738 /* padding not required if srcsize is set */ 739 static int sldns_b64_pton_base(char const *src, size_t srcsize, uint8_t *target, 740 size_t targsize, int base64url) 741 { 742 const uint8_t pad64 = 64; /* is 64th in the b64 array */ 743 const char* s = src; 744 uint8_t in[4]; 745 size_t o = 0, incount = 0; 746 int check_padding = (srcsize) ? 0 : 1; 747 748 while(*s && (check_padding || srcsize)) { 749 /* skip any character that is not base64 */ 750 /* conceptually we do: 751 const char* b64 = pad'=' is appended to array 752 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 753 const char* d = strchr(b64, *s++); 754 and use d-b64; 755 */ 756 char d = *s++; 757 srcsize--; 758 if(d <= 'Z' && d >= 'A') 759 d -= 'A'; 760 else if(d <= 'z' && d >= 'a') 761 d = d - 'a' + 26; 762 else if(d <= '9' && d >= '0') 763 d = d - '0' + 52; 764 else if(!base64url && d == '+') 765 d = 62; 766 else if(base64url && d == '-') 767 d = 62; 768 else if(!base64url && d == '/') 769 d = 63; 770 else if(base64url && d == '_') 771 d = 63; 772 else if(d == '=') { 773 if(!check_padding) 774 continue; 775 d = 64; 776 } else continue; 777 778 in[incount++] = (uint8_t)d; 779 /* work on block of 4, unless padding is not used and there are 780 * less than 4 chars left */ 781 if(incount != 4 && (check_padding || srcsize)) 782 continue; 783 assert(!check_padding || incount==4); 784 /* process whole block of 4 characters into 3 output bytes */ 785 if((incount == 2 || 786 (incount == 4 && in[3] == pad64 && in[2] == pad64))) { /* A B = = */ 787 if(o+1 > targsize) 788 return -1; 789 target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); 790 o += 1; 791 break; /* we are done */ 792 } else if(incount == 3 || 793 (incount == 4 && in[3] == pad64)) { /* A B C = */ 794 if(o+2 > targsize) 795 return -1; 796 target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); 797 target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2); 798 o += 2; 799 break; /* we are done */ 800 } else { 801 if(incount != 4 || o+3 > targsize) 802 return -1; 803 /* write xxxxxxyy yyyyzzzz zzwwwwww */ 804 target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); 805 target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2); 806 target[o+2]= ((in[2]&0x03)<<6) | in[3]; 807 o += 3; 808 } 809 incount = 0; 810 } 811 return (int)o; 812 } 813 814 int sldns_b64_pton(char const *src, uint8_t *target, size_t targsize) 815 { 816 return sldns_b64_pton_base(src, 0, target, targsize, 0); 817 } 818 819 int sldns_b64url_pton(char const *src, size_t srcsize, uint8_t *target, 820 size_t targsize) 821 { 822 if(!srcsize) { 823 return 0; 824 } 825 return sldns_b64_pton_base(src, srcsize, target, targsize, 1); 826 } 827 828 int sldns_b64_contains_nonurl(char const *src, size_t srcsize) 829 { 830 const char* s = src; 831 while(*s && srcsize) { 832 char d = *s++; 833 srcsize--; 834 /* the '+' and the '/' and padding '=' is not allowed in b64 835 * url encoding */ 836 if(d == '+' || d == '/' || d == '=') { 837 return 1; 838 } 839 } 840 return 0; 841 } 842