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 ATTR_FALLTHROUGH 440 /* fallthrough */ 441 case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c]; 442 443 /* ........ .......3 3333.... ........ ........ */ 444 c = src[2] >> 4 ; 445 ATTR_FALLTHROUGH 446 /* fallthrough */ 447 case 2: dst[3] = b32[(src[1] & 0x01) << 4 | c]; 448 449 /* ........ ..22222. ........ ........ ........ */ 450 dst[2] = b32[(src[1] & 0x3e) >> 1]; 451 452 /* .....111 11...... ........ ........ ........ */ 453 c = src[1] >> 6 ; 454 ATTR_FALLTHROUGH 455 /* fallthrough */ 456 case 1: dst[1] = b32[(src[0] & 0x07) << 2 | c]; 457 458 /* 00000... ........ ........ ........ ........ */ 459 dst[0] = b32[ src[0] >> 3]; 460 } 461 /* Add padding */ 462 if (add_padding) { 463 switch (src_sz) { 464 case 1: dst[2] = '='; 465 dst[3] = '='; 466 ATTR_FALLTHROUGH 467 /* fallthrough */ 468 case 2: dst[4] = '='; 469 ATTR_FALLTHROUGH 470 /* fallthrough */ 471 case 3: dst[5] = '='; 472 dst[6] = '='; 473 ATTR_FALLTHROUGH 474 /* fallthrough */ 475 case 4: dst[7] = '='; 476 } 477 } 478 return (int)ret_sz; 479 } 480 481 int 482 sldns_b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) 483 { 484 return sldns_b32_ntop_base(src, src_sz, dst, dst_sz, 0, 1); 485 } 486 487 int 488 sldns_b32_ntop_extended_hex(const uint8_t* src, size_t src_sz, 489 char* dst, size_t dst_sz) 490 { 491 return sldns_b32_ntop_base(src, src_sz, dst, dst_sz, 1, 1); 492 } 493 494 size_t sldns_b32_pton_calculate_size(size_t src_text_length) 495 { 496 return src_text_length * 5 / 8; 497 } 498 499 static int 500 sldns_b32_pton_base(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz, 501 int extended_hex, int check_padding) 502 { 503 size_t i = 0; 504 char ch = '\0'; 505 uint8_t buf[8]; 506 uint8_t* start = dst; 507 508 while (src_sz) { 509 /* Collect 8 characters in buf (if possible) */ 510 for (i = 0; i < 8; i++) { 511 512 do { 513 ch = *src++; 514 --src_sz; 515 516 } while (isspace((unsigned char)ch) && src_sz > 0); 517 518 if (ch == '=' || ch == '\0') 519 break; 520 521 else if (extended_hex) 522 523 if (ch >= '0' && ch <= '9') 524 buf[i] = (uint8_t)ch - '0'; 525 else if (ch >= 'a' && ch <= 'v') 526 buf[i] = (uint8_t)ch - 'a' + 10; 527 else if (ch >= 'A' && ch <= 'V') 528 buf[i] = (uint8_t)ch - 'A' + 10; 529 else 530 return -1; 531 532 else if (ch >= 'a' && ch <= 'z') 533 buf[i] = (uint8_t)ch - 'a'; 534 else if (ch >= 'A' && ch <= 'Z') 535 buf[i] = (uint8_t)ch - 'A'; 536 else if (ch >= '2' && ch <= '7') 537 buf[i] = (uint8_t)ch - '2' + 26; 538 else 539 return -1; 540 } 541 /* Less that 8 characters. We're done. */ 542 if (i < 8) 543 break; 544 545 /* Enough space available at the destination? */ 546 if (dst_sz < 5) 547 return -1; 548 549 /* 00000... ........ ........ ........ ........ */ 550 /* .....111 11...... ........ ........ ........ */ 551 dst[0] = buf[0] << 3 | buf[1] >> 2; 552 553 /* .....111 11...... ........ ........ ........ */ 554 /* ........ ..22222. ........ ........ ........ */ 555 /* ........ .......3 3333.... ........ ........ */ 556 dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; 557 558 /* ........ .......3 3333.... ........ ........ */ 559 /* ........ ........ ....4444 4....... ........ */ 560 dst[2] = buf[3] << 4 | buf[4] >> 1; 561 562 /* ........ ........ ....4444 4....... ........ */ 563 /* ........ ........ ........ .55555.. ........ */ 564 /* ........ ........ ........ ......66 666..... */ 565 dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; 566 567 /* ........ ........ ........ ......66 666..... */ 568 /* ........ ........ ........ ........ ...77777 */ 569 dst[4] = buf[6] << 5 | buf[7]; 570 571 dst += 5; 572 dst_sz -= 5; 573 } 574 /* Not ending on a eight byte boundary? */ 575 if (i > 0 && i < 8) { 576 577 /* Enough space available at the destination? */ 578 if (dst_sz < (i + 1) / 2) 579 return -1; 580 581 switch (i) { 582 case 7: /* ........ ........ ........ ......66 666..... */ 583 /* ........ ........ ........ .55555.. ........ */ 584 /* ........ ........ ....4444 4....... ........ */ 585 dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; 586 ATTR_FALLTHROUGH 587 /* fallthrough */ 588 589 case 5: /* ........ ........ ....4444 4....... ........ */ 590 /* ........ .......3 3333.... ........ ........ */ 591 dst[2] = buf[3] << 4 | buf[4] >> 1; 592 ATTR_FALLTHROUGH 593 /* fallthrough */ 594 595 case 4: /* ........ .......3 3333.... ........ ........ */ 596 /* ........ ..22222. ........ ........ ........ */ 597 /* .....111 11...... ........ ........ ........ */ 598 dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; 599 ATTR_FALLTHROUGH 600 /* fallthrough */ 601 602 case 2: /* .....111 11...... ........ ........ ........ */ 603 /* 00000... ........ ........ ........ ........ */ 604 dst[0] = buf[0] << 3 | buf[1] >> 2; 605 606 break; 607 608 default: 609 return -1; 610 } 611 dst += (i + 1) / 2; 612 613 if (check_padding) { 614 /* Check remaining padding characters */ 615 if (ch != '=') 616 return -1; 617 618 /* One down, 8 - i - 1 more to come... */ 619 for (i = 8 - i - 1; i > 0; i--) { 620 621 do { 622 if (src_sz == 0) 623 return -1; 624 ch = *src++; 625 src_sz--; 626 627 } while (isspace((unsigned char)ch)); 628 629 if (ch != '=') 630 return -1; 631 } 632 } 633 } 634 return dst - start; 635 } 636 637 int 638 sldns_b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) 639 { 640 return sldns_b32_pton_base(src, src_sz, dst, dst_sz, 0, 1); 641 } 642 643 int 644 sldns_b32_pton_extended_hex(const char* src, size_t src_sz, 645 uint8_t* dst, size_t dst_sz) 646 { 647 return sldns_b32_pton_base(src, src_sz, dst, dst_sz, 1, 1); 648 } 649 650 size_t sldns_b64_ntop_calculate_size(size_t srcsize) 651 { 652 return ((((srcsize + 2) / 3) * 4) + 1); 653 } 654 655 /* RFC 1521, section 5.2. 656 * 657 * The encoding process represents 24-bit groups of input bits as output 658 * strings of 4 encoded characters. Proceeding from left to right, a 659 * 24-bit input group is formed by concatenating 3 8-bit input groups. 660 * These 24 bits are then treated as 4 concatenated 6-bit groups, each 661 * of which is translated into a single digit in the base64 alphabet. 662 * 663 * This routine does not insert spaces or linebreaks after 76 characters. 664 */ 665 static int sldns_b64_ntop_base(uint8_t const *src, size_t srclength, 666 char *target, size_t targsize, int base64url, int padding) 667 { 668 char* b64; 669 const char pad64 = '='; 670 size_t i = 0, o = 0; 671 if(base64url) 672 b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123" 673 "456789-_"; 674 else 675 b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123" 676 "456789+/"; 677 if(targsize < sldns_b64_ntop_calculate_size(srclength)) 678 return -1; 679 /* whole chunks: xxxxxxyy yyyyzzzz zzwwwwww */ 680 while(i+3 <= srclength) { 681 if(o+4 > targsize) return -1; 682 target[o] = b64[src[i] >> 2]; 683 target[o+1] = b64[ ((src[i]&0x03)<<4) | (src[i+1]>>4) ]; 684 target[o+2] = b64[ ((src[i+1]&0x0f)<<2) | (src[i+2]>>6) ]; 685 target[o+3] = b64[ (src[i+2]&0x3f) ]; 686 i += 3; 687 o += 4; 688 } 689 /* remainder */ 690 switch(srclength - i) { 691 case 2: 692 /* two at end, converted into A B C = */ 693 target[o] = b64[src[i] >> 2]; 694 target[o+1] = b64[ ((src[i]&0x03)<<4) | (src[i+1]>>4) ]; 695 target[o+2] = b64[ ((src[i+1]&0x0f)<<2) ]; 696 if(padding) { 697 target[o+3] = pad64; 698 /* i += 2; */ 699 o += 4; 700 } else { 701 o += 3; 702 } 703 break; 704 case 1: 705 /* one at end, converted into A B = = */ 706 target[o] = b64[src[i] >> 2]; 707 target[o+1] = b64[ ((src[i]&0x03)<<4) ]; 708 if(padding) { 709 target[o+2] = pad64; 710 target[o+3] = pad64; 711 /* i += 1; */ 712 o += 4; 713 } else { 714 o += 2; 715 } 716 break; 717 case 0: 718 default: 719 /* nothing */ 720 break; 721 } 722 /* assert: i == srclength */ 723 if(o+1 > targsize) return -1; 724 target[o] = 0; 725 return (int)o; 726 } 727 728 int sldns_b64_ntop(uint8_t const *src, size_t srclength, char *target, 729 size_t targsize) 730 { 731 return sldns_b64_ntop_base(src, srclength, target, targsize, 732 0 /* no base64url */, 1 /* padding */); 733 } 734 735 int sldns_b64url_ntop(uint8_t const *src, size_t srclength, char *target, 736 size_t targsize) 737 { 738 return sldns_b64_ntop_base(src, srclength, target, targsize, 739 1 /* base64url */, 0 /* no padding */); 740 } 741 742 size_t sldns_b64_pton_calculate_size(size_t srcsize) 743 { 744 return (((((srcsize + 3) / 4) * 3)) + 1); 745 } 746 747 /* padding not required if srcsize is set */ 748 static int sldns_b64_pton_base(char const *src, size_t srcsize, uint8_t *target, 749 size_t targsize, int base64url) 750 { 751 const uint8_t pad64 = 64; /* is 64th in the b64 array */ 752 const char* s = src; 753 uint8_t in[4]; 754 size_t o = 0, incount = 0; 755 int check_padding = (srcsize) ? 0 : 1; 756 757 while(*s && (check_padding || srcsize)) { 758 /* skip any character that is not base64 */ 759 /* conceptually we do: 760 const char* b64 = pad'=' is appended to array 761 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 762 const char* d = strchr(b64, *s++); 763 and use d-b64; 764 */ 765 char d = *s++; 766 srcsize--; 767 if(d <= 'Z' && d >= 'A') 768 d -= 'A'; 769 else if(d <= 'z' && d >= 'a') 770 d = d - 'a' + 26; 771 else if(d <= '9' && d >= '0') 772 d = d - '0' + 52; 773 else if(!base64url && d == '+') 774 d = 62; 775 else if(base64url && d == '-') 776 d = 62; 777 else if(!base64url && d == '/') 778 d = 63; 779 else if(base64url && d == '_') 780 d = 63; 781 else if(d == '=') { 782 if(!check_padding) 783 continue; 784 d = 64; 785 } else continue; 786 787 in[incount++] = (uint8_t)d; 788 /* work on block of 4, unless padding is not used and there are 789 * less than 4 chars left */ 790 if(incount != 4 && (check_padding || srcsize)) 791 continue; 792 assert(!check_padding || incount==4); 793 /* process whole block of 4 characters into 3 output bytes */ 794 if((incount == 2 || 795 (incount == 4 && in[3] == pad64 && in[2] == pad64))) { /* A B = = */ 796 if(o+1 > targsize) 797 return -1; 798 target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); 799 o += 1; 800 break; /* we are done */ 801 } else if(incount == 3 || 802 (incount == 4 && in[3] == pad64)) { /* A B C = */ 803 if(o+2 > targsize) 804 return -1; 805 target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); 806 target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2); 807 o += 2; 808 break; /* we are done */ 809 } else { 810 if(incount != 4 || o+3 > targsize) 811 return -1; 812 /* write xxxxxxyy yyyyzzzz zzwwwwww */ 813 target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); 814 target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2); 815 target[o+2]= ((in[2]&0x03)<<6) | in[3]; 816 o += 3; 817 } 818 incount = 0; 819 } 820 return (int)o; 821 } 822 823 int sldns_b64_pton(char const *src, uint8_t *target, size_t targsize) 824 { 825 return sldns_b64_pton_base(src, 0, target, targsize, 0); 826 } 827 828 int sldns_b64url_pton(char const *src, size_t srcsize, uint8_t *target, 829 size_t targsize) 830 { 831 if(!srcsize) { 832 return 0; 833 } 834 return sldns_b64_pton_base(src, srcsize, target, targsize, 1); 835 } 836 837 int sldns_b64_contains_nonurl(char const *src, size_t srcsize) 838 { 839 const char* s = src; 840 while(*s && srcsize) { 841 char d = *s++; 842 srcsize--; 843 /* the '+' and the '/' and padding '=' is not allowed in b64 844 * url encoding */ 845 if(d == '+' || d == '/' || d == '=') { 846 return 1; 847 } 848 } 849 return 0; 850 } 851