1266077Sdes/* 2266077Sdes * parseutil.c - parse utilities for string and wire conversion 3266077Sdes * 4266077Sdes * (c) NLnet Labs, 2004-2006 5266077Sdes * 6266077Sdes * See the file LICENSE for the license 7266077Sdes */ 8266077Sdes/** 9266077Sdes * \file 10266077Sdes * 11266077Sdes * Utility functions for parsing, base32(DNS variant) and base64 encoding 12266077Sdes * and decoding, Hex, Time units, Escape codes. 13266077Sdes */ 14266077Sdes 15266077Sdes#include "config.h" 16287915Sdes#include "sldns/parseutil.h" 17266077Sdes#include <sys/time.h> 18266077Sdes#include <time.h> 19266077Sdes#include <ctype.h> 20266077Sdes 21266077Sdessldns_lookup_table * 22266077Sdessldns_lookup_by_name(sldns_lookup_table *table, const char *name) 23266077Sdes{ 24266077Sdes while (table->name != NULL) { 25266077Sdes if (strcasecmp(name, table->name) == 0) 26266077Sdes return table; 27266077Sdes table++; 28266077Sdes } 29266077Sdes return NULL; 30266077Sdes} 31266077Sdes 32266077Sdessldns_lookup_table * 33266077Sdessldns_lookup_by_id(sldns_lookup_table *table, int id) 34266077Sdes{ 35266077Sdes while (table->name != NULL) { 36266077Sdes if (table->id == id) 37266077Sdes return table; 38266077Sdes table++; 39266077Sdes } 40266077Sdes return NULL; 41266077Sdes} 42266077Sdes 43266077Sdes/* Number of days per month (except for February in leap years). */ 44266077Sdesstatic const int mdays[] = { 45266077Sdes 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 46266077Sdes}; 47266077Sdes 48266077Sdes#define LDNS_MOD(x,y) (((x) % (y) < 0) ? ((x) % (y) + (y)) : ((x) % (y))) 49266077Sdes#define LDNS_DIV(x,y) (((x) % (y) < 0) ? ((x) / (y) - 1 ) : ((x) / (y))) 50266077Sdes 51266077Sdesstatic int 52266077Sdesis_leap_year(int year) 53266077Sdes{ 54266077Sdes return LDNS_MOD(year, 4) == 0 && (LDNS_MOD(year, 100) != 0 55266077Sdes || LDNS_MOD(year, 400) == 0); 56266077Sdes} 57266077Sdes 58266077Sdesstatic int 59266077Sdesleap_days(int y1, int y2) 60266077Sdes{ 61266077Sdes --y1; 62266077Sdes --y2; 63266077Sdes return (LDNS_DIV(y2, 4) - LDNS_DIV(y1, 4)) - 64266077Sdes (LDNS_DIV(y2, 100) - LDNS_DIV(y1, 100)) + 65266077Sdes (LDNS_DIV(y2, 400) - LDNS_DIV(y1, 400)); 66266077Sdes} 67266077Sdes 68266077Sdes/* 69266077Sdes * Code adapted from Python 2.4.1 sources (Lib/calendar.py). 70266077Sdes */ 71266077Sdestime_t 72266077Sdessldns_mktime_from_utc(const struct tm *tm) 73266077Sdes{ 74266077Sdes int year = 1900 + tm->tm_year; 75266077Sdes time_t days = 365 * ((time_t) year - 1970) + leap_days(1970, year); 76266077Sdes time_t hours; 77266077Sdes time_t minutes; 78266077Sdes time_t seconds; 79266077Sdes int i; 80266077Sdes 81266077Sdes for (i = 0; i < tm->tm_mon; ++i) { 82266077Sdes days += mdays[i]; 83266077Sdes } 84266077Sdes if (tm->tm_mon > 1 && is_leap_year(year)) { 85266077Sdes ++days; 86266077Sdes } 87266077Sdes days += tm->tm_mday - 1; 88266077Sdes 89266077Sdes hours = days * 24 + tm->tm_hour; 90266077Sdes minutes = hours * 60 + tm->tm_min; 91266077Sdes seconds = minutes * 60 + tm->tm_sec; 92266077Sdes 93266077Sdes return seconds; 94266077Sdes} 95266077Sdes 96266077Sdes#if SIZEOF_TIME_T <= 4 97266077Sdes 98266077Sdesstatic void 99266077Sdessldns_year_and_yday_from_days_since_epoch(int64_t days, struct tm *result) 100266077Sdes{ 101266077Sdes int year = 1970; 102266077Sdes int new_year; 103266077Sdes 104266077Sdes while (days < 0 || days >= (int64_t) (is_leap_year(year) ? 366 : 365)) { 105266077Sdes new_year = year + (int) LDNS_DIV(days, 365); 106266077Sdes days -= (new_year - year) * 365; 107266077Sdes days -= leap_days(year, new_year); 108266077Sdes year = new_year; 109266077Sdes } 110266077Sdes result->tm_year = year; 111266077Sdes result->tm_yday = (int) days; 112266077Sdes} 113266077Sdes 114266077Sdes/* Number of days per month in a leap year. */ 115266077Sdesstatic const int leap_year_mdays[] = { 116266077Sdes 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 117266077Sdes}; 118266077Sdes 119266077Sdesstatic void 120266077Sdessldns_mon_and_mday_from_year_and_yday(struct tm *result) 121266077Sdes{ 122266077Sdes int idays = result->tm_yday; 123266077Sdes const int *mon_lengths = is_leap_year(result->tm_year) ? 124266077Sdes leap_year_mdays : mdays; 125266077Sdes 126266077Sdes result->tm_mon = 0; 127266077Sdes while (idays >= mon_lengths[result->tm_mon]) { 128266077Sdes idays -= mon_lengths[result->tm_mon++]; 129266077Sdes } 130266077Sdes result->tm_mday = idays + 1; 131266077Sdes} 132266077Sdes 133266077Sdesstatic void 134266077Sdessldns_wday_from_year_and_yday(struct tm *result) 135266077Sdes{ 136266077Sdes result->tm_wday = 4 /* 1-1-1970 was a thursday */ 137266077Sdes + LDNS_MOD((result->tm_year - 1970), 7) * LDNS_MOD(365, 7) 138266077Sdes + leap_days(1970, result->tm_year) 139266077Sdes + result->tm_yday; 140266077Sdes result->tm_wday = LDNS_MOD(result->tm_wday, 7); 141266077Sdes if (result->tm_wday < 0) { 142266077Sdes result->tm_wday += 7; 143266077Sdes } 144266077Sdes} 145266077Sdes 146266077Sdesstatic struct tm * 147266077Sdessldns_gmtime64_r(int64_t clock, struct tm *result) 148266077Sdes{ 149266077Sdes result->tm_isdst = 0; 150266077Sdes result->tm_sec = (int) LDNS_MOD(clock, 60); 151266077Sdes clock = LDNS_DIV(clock, 60); 152266077Sdes result->tm_min = (int) LDNS_MOD(clock, 60); 153266077Sdes clock = LDNS_DIV(clock, 60); 154266077Sdes result->tm_hour = (int) LDNS_MOD(clock, 24); 155266077Sdes clock = LDNS_DIV(clock, 24); 156266077Sdes 157266077Sdes sldns_year_and_yday_from_days_since_epoch(clock, result); 158266077Sdes sldns_mon_and_mday_from_year_and_yday(result); 159266077Sdes sldns_wday_from_year_and_yday(result); 160266077Sdes result->tm_year -= 1900; 161266077Sdes 162266077Sdes return result; 163266077Sdes} 164266077Sdes 165266077Sdes#endif /* SIZEOF_TIME_T <= 4 */ 166266077Sdes 167266077Sdesstatic int64_t 168356345Scysldns_serial_arithmetics_time(int32_t time, time_t now) 169266077Sdes{ 170366095Scy int32_t offset = (int32_t)((uint32_t) time - (uint32_t) now); 171266077Sdes return (int64_t) now + offset; 172266077Sdes} 173266077Sdes 174266077Sdesstruct tm * 175356345Scysldns_serial_arithmetics_gmtime_r(int32_t time, time_t now, struct tm *result) 176266077Sdes{ 177266077Sdes#if SIZEOF_TIME_T <= 4 178356345Scy int64_t secs_since_epoch = sldns_serial_arithmetics_time(time, now); 179266077Sdes return sldns_gmtime64_r(secs_since_epoch, result); 180266077Sdes#else 181356345Scy time_t secs_since_epoch = sldns_serial_arithmetics_time(time, now); 182266077Sdes return gmtime_r(&secs_since_epoch, result); 183266077Sdes#endif 184266077Sdes} 185266077Sdes 186266077Sdesint 187266077Sdessldns_hexdigit_to_int(char ch) 188266077Sdes{ 189266077Sdes switch (ch) { 190266077Sdes case '0': return 0; 191266077Sdes case '1': return 1; 192266077Sdes case '2': return 2; 193266077Sdes case '3': return 3; 194266077Sdes case '4': return 4; 195266077Sdes case '5': return 5; 196266077Sdes case '6': return 6; 197266077Sdes case '7': return 7; 198266077Sdes case '8': return 8; 199266077Sdes case '9': return 9; 200266077Sdes case 'a': case 'A': return 10; 201266077Sdes case 'b': case 'B': return 11; 202266077Sdes case 'c': case 'C': return 12; 203266077Sdes case 'd': case 'D': return 13; 204266077Sdes case 'e': case 'E': return 14; 205266077Sdes case 'f': case 'F': return 15; 206266077Sdes default: 207266077Sdes return -1; 208266077Sdes } 209266077Sdes} 210266077Sdes 211266077Sdesuint32_t 212266077Sdessldns_str2period(const char *nptr, const char **endptr) 213266077Sdes{ 214266077Sdes int sign = 0; 215266077Sdes uint32_t i = 0; 216266077Sdes uint32_t seconds = 0; 217266077Sdes 218266077Sdes for(*endptr = nptr; **endptr; (*endptr)++) { 219266077Sdes switch (**endptr) { 220266077Sdes case ' ': 221266077Sdes case '\t': 222266077Sdes break; 223266077Sdes case '-': 224266077Sdes if(sign == 0) { 225266077Sdes sign = -1; 226266077Sdes } else { 227266077Sdes return seconds; 228266077Sdes } 229266077Sdes break; 230266077Sdes case '+': 231266077Sdes if(sign == 0) { 232266077Sdes sign = 1; 233266077Sdes } else { 234266077Sdes return seconds; 235266077Sdes } 236266077Sdes break; 237266077Sdes case 's': 238266077Sdes case 'S': 239266077Sdes seconds += i; 240266077Sdes i = 0; 241266077Sdes break; 242266077Sdes case 'm': 243266077Sdes case 'M': 244266077Sdes seconds += i * 60; 245266077Sdes i = 0; 246266077Sdes break; 247266077Sdes case 'h': 248266077Sdes case 'H': 249266077Sdes seconds += i * 60 * 60; 250266077Sdes i = 0; 251266077Sdes break; 252266077Sdes case 'd': 253266077Sdes case 'D': 254266077Sdes seconds += i * 60 * 60 * 24; 255266077Sdes i = 0; 256266077Sdes break; 257266077Sdes case 'w': 258266077Sdes case 'W': 259266077Sdes seconds += i * 60 * 60 * 24 * 7; 260266077Sdes i = 0; 261266077Sdes break; 262266077Sdes case '0': 263266077Sdes case '1': 264266077Sdes case '2': 265266077Sdes case '3': 266266077Sdes case '4': 267266077Sdes case '5': 268266077Sdes case '6': 269266077Sdes case '7': 270266077Sdes case '8': 271266077Sdes case '9': 272266077Sdes i *= 10; 273266077Sdes i += (**endptr - '0'); 274266077Sdes break; 275266077Sdes default: 276266077Sdes seconds += i; 277266077Sdes /* disregard signedness */ 278266077Sdes return seconds; 279266077Sdes } 280266077Sdes } 281266077Sdes seconds += i; 282266077Sdes /* disregard signedness */ 283266077Sdes return seconds; 284266077Sdes} 285266077Sdes 286266077Sdesint 287266077Sdessldns_parse_escape(uint8_t *ch_p, const char** str_p) 288266077Sdes{ 289266077Sdes uint16_t val; 290266077Sdes 291276541Sdes if ((*str_p)[0] && isdigit((unsigned char)(*str_p)[0]) && 292276541Sdes (*str_p)[1] && isdigit((unsigned char)(*str_p)[1]) && 293276541Sdes (*str_p)[2] && isdigit((unsigned char)(*str_p)[2])) { 294266077Sdes 295266077Sdes val = (uint16_t)(((*str_p)[0] - '0') * 100 + 296266077Sdes ((*str_p)[1] - '0') * 10 + 297266077Sdes ((*str_p)[2] - '0')); 298266077Sdes 299266077Sdes if (val > 255) { 300266077Sdes goto error; 301266077Sdes } 302266077Sdes *ch_p = (uint8_t)val; 303266077Sdes *str_p += 3; 304266077Sdes return 1; 305266077Sdes 306276541Sdes } else if ((*str_p)[0] && !isdigit((unsigned char)(*str_p)[0])) { 307266077Sdes 308266077Sdes *ch_p = (uint8_t)*(*str_p)++; 309266077Sdes return 1; 310266077Sdes } 311266077Sdeserror: 312266077Sdes *str_p = NULL; 313266077Sdes return 0; /* LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE */ 314266077Sdes} 315266077Sdes 316266077Sdes/** parse one character, with escape codes */ 317266077Sdesint 318266077Sdessldns_parse_char(uint8_t *ch_p, const char** str_p) 319266077Sdes{ 320266077Sdes switch (**str_p) { 321266077Sdes 322266077Sdes case '\0': return 0; 323266077Sdes 324266077Sdes case '\\': *str_p += 1; 325266077Sdes return sldns_parse_escape(ch_p, str_p); 326266077Sdes 327266077Sdes default: *ch_p = (uint8_t)*(*str_p)++; 328266077Sdes return 1; 329266077Sdes } 330266077Sdes} 331266077Sdes 332266077Sdessize_t sldns_b32_ntop_calculate_size(size_t src_data_length) 333266077Sdes{ 334266077Sdes return src_data_length == 0 ? 0 : ((src_data_length - 1) / 5 + 1) * 8; 335266077Sdes} 336266077Sdes 337266077Sdessize_t sldns_b32_ntop_calculate_size_no_padding(size_t src_data_length) 338266077Sdes{ 339266077Sdes return ((src_data_length + 3) * 8 / 5) - 4; 340266077Sdes} 341266077Sdes 342266077Sdesstatic int 343266077Sdessldns_b32_ntop_base(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz, 344266077Sdes int extended_hex, int add_padding) 345266077Sdes{ 346266077Sdes size_t ret_sz; 347266077Sdes const char* b32 = extended_hex ? "0123456789abcdefghijklmnopqrstuv" 348266077Sdes : "abcdefghijklmnopqrstuvwxyz234567"; 349266077Sdes 350266077Sdes size_t c = 0; /* c is used to carry partial base32 character over 351266077Sdes * byte boundaries for sizes with a remainder. 352266077Sdes * (i.e. src_sz % 5 != 0) 353266077Sdes */ 354266077Sdes 355266077Sdes ret_sz = add_padding ? sldns_b32_ntop_calculate_size(src_sz) 356266077Sdes : sldns_b32_ntop_calculate_size_no_padding(src_sz); 357266077Sdes 358266077Sdes /* Do we have enough space? */ 359266077Sdes if (dst_sz < ret_sz + 1) 360266077Sdes return -1; 361266077Sdes 362266077Sdes /* We know the size; terminate the string */ 363266077Sdes dst[ret_sz] = '\0'; 364266077Sdes 365266077Sdes /* First process all chunks of five */ 366266077Sdes while (src_sz >= 5) { 367266077Sdes /* 00000... ........ ........ ........ ........ */ 368266077Sdes dst[0] = b32[(src[0] ) >> 3]; 369266077Sdes 370266077Sdes /* .....111 11...... ........ ........ ........ */ 371266077Sdes dst[1] = b32[(src[0] & 0x07) << 2 | src[1] >> 6]; 372266077Sdes 373266077Sdes /* ........ ..22222. ........ ........ ........ */ 374266077Sdes dst[2] = b32[(src[1] & 0x3e) >> 1]; 375266077Sdes 376266077Sdes /* ........ .......3 3333.... ........ ........ */ 377266077Sdes dst[3] = b32[(src[1] & 0x01) << 4 | src[2] >> 4]; 378266077Sdes 379266077Sdes /* ........ ........ ....4444 4....... ........ */ 380266077Sdes dst[4] = b32[(src[2] & 0x0f) << 1 | src[3] >> 7]; 381266077Sdes 382266077Sdes /* ........ ........ ........ .55555.. ........ */ 383266077Sdes dst[5] = b32[(src[3] & 0x7c) >> 2]; 384266077Sdes 385266077Sdes /* ........ ........ ........ ......66 666..... */ 386266077Sdes dst[6] = b32[(src[3] & 0x03) << 3 | src[4] >> 5]; 387266077Sdes 388266077Sdes /* ........ ........ ........ ........ ...77777 */ 389266077Sdes dst[7] = b32[(src[4] & 0x1f) ]; 390266077Sdes 391266077Sdes src_sz -= 5; 392266077Sdes src += 5; 393266077Sdes dst += 8; 394266077Sdes } 395266077Sdes /* Process what remains */ 396266077Sdes switch (src_sz) { 397266077Sdes case 4: /* ........ ........ ........ ......66 666..... */ 398266077Sdes dst[6] = b32[(src[3] & 0x03) << 3]; 399266077Sdes 400266077Sdes /* ........ ........ ........ .55555.. ........ */ 401266077Sdes dst[5] = b32[(src[3] & 0x7c) >> 2]; 402266077Sdes 403266077Sdes /* ........ ........ ....4444 4....... ........ */ 404266077Sdes c = src[3] >> 7 ; 405356345Scy /* fallthrough */ 406266077Sdes case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c]; 407266077Sdes 408266077Sdes /* ........ .......3 3333.... ........ ........ */ 409266077Sdes c = src[2] >> 4 ; 410356345Scy /* fallthrough */ 411266077Sdes case 2: dst[3] = b32[(src[1] & 0x01) << 4 | c]; 412266077Sdes 413266077Sdes /* ........ ..22222. ........ ........ ........ */ 414266077Sdes dst[2] = b32[(src[1] & 0x3e) >> 1]; 415266077Sdes 416266077Sdes /* .....111 11...... ........ ........ ........ */ 417266077Sdes c = src[1] >> 6 ; 418356345Scy /* fallthrough */ 419266077Sdes case 1: dst[1] = b32[(src[0] & 0x07) << 2 | c]; 420266077Sdes 421266077Sdes /* 00000... ........ ........ ........ ........ */ 422266077Sdes dst[0] = b32[ src[0] >> 3]; 423266077Sdes } 424266077Sdes /* Add padding */ 425266077Sdes if (add_padding) { 426266077Sdes switch (src_sz) { 427266077Sdes case 1: dst[2] = '='; 428266077Sdes dst[3] = '='; 429356345Scy /* fallthrough */ 430266077Sdes case 2: dst[4] = '='; 431356345Scy /* fallthrough */ 432266077Sdes case 3: dst[5] = '='; 433266077Sdes dst[6] = '='; 434356345Scy /* fallthrough */ 435266077Sdes case 4: dst[7] = '='; 436266077Sdes } 437266077Sdes } 438266077Sdes return (int)ret_sz; 439266077Sdes} 440266077Sdes 441266077Sdesint 442266077Sdessldns_b32_ntop(const uint8_t* src, size_t src_sz, char* dst, size_t dst_sz) 443266077Sdes{ 444266077Sdes return sldns_b32_ntop_base(src, src_sz, dst, dst_sz, 0, 1); 445266077Sdes} 446266077Sdes 447266077Sdesint 448266077Sdessldns_b32_ntop_extended_hex(const uint8_t* src, size_t src_sz, 449266077Sdes char* dst, size_t dst_sz) 450266077Sdes{ 451266077Sdes return sldns_b32_ntop_base(src, src_sz, dst, dst_sz, 1, 1); 452266077Sdes} 453266077Sdes 454266077Sdessize_t sldns_b32_pton_calculate_size(size_t src_text_length) 455266077Sdes{ 456266077Sdes return src_text_length * 5 / 8; 457266077Sdes} 458266077Sdes 459266077Sdesstatic int 460266077Sdessldns_b32_pton_base(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz, 461266077Sdes int extended_hex, int check_padding) 462266077Sdes{ 463266077Sdes size_t i = 0; 464266077Sdes char ch = '\0'; 465266077Sdes uint8_t buf[8]; 466266077Sdes uint8_t* start = dst; 467266077Sdes 468266077Sdes while (src_sz) { 469266077Sdes /* Collect 8 characters in buf (if possible) */ 470266077Sdes for (i = 0; i < 8; i++) { 471266077Sdes 472266077Sdes do { 473266077Sdes ch = *src++; 474266077Sdes --src_sz; 475266077Sdes 476276541Sdes } while (isspace((unsigned char)ch) && src_sz > 0); 477266077Sdes 478266077Sdes if (ch == '=' || ch == '\0') 479266077Sdes break; 480266077Sdes 481266077Sdes else if (extended_hex) 482266077Sdes 483266077Sdes if (ch >= '0' && ch <= '9') 484266077Sdes buf[i] = (uint8_t)ch - '0'; 485266077Sdes else if (ch >= 'a' && ch <= 'v') 486266077Sdes buf[i] = (uint8_t)ch - 'a' + 10; 487266077Sdes else if (ch >= 'A' && ch <= 'V') 488266077Sdes buf[i] = (uint8_t)ch - 'A' + 10; 489266077Sdes else 490266077Sdes return -1; 491266077Sdes 492266077Sdes else if (ch >= 'a' && ch <= 'z') 493266077Sdes buf[i] = (uint8_t)ch - 'a'; 494266077Sdes else if (ch >= 'A' && ch <= 'Z') 495266077Sdes buf[i] = (uint8_t)ch - 'A'; 496266077Sdes else if (ch >= '2' && ch <= '7') 497266077Sdes buf[i] = (uint8_t)ch - '2' + 26; 498266077Sdes else 499266077Sdes return -1; 500266077Sdes } 501266077Sdes /* Less that 8 characters. We're done. */ 502266077Sdes if (i < 8) 503266077Sdes break; 504266077Sdes 505266077Sdes /* Enough space available at the destination? */ 506266077Sdes if (dst_sz < 5) 507266077Sdes return -1; 508266077Sdes 509266077Sdes /* 00000... ........ ........ ........ ........ */ 510266077Sdes /* .....111 11...... ........ ........ ........ */ 511266077Sdes dst[0] = buf[0] << 3 | buf[1] >> 2; 512266077Sdes 513266077Sdes /* .....111 11...... ........ ........ ........ */ 514266077Sdes /* ........ ..22222. ........ ........ ........ */ 515266077Sdes /* ........ .......3 3333.... ........ ........ */ 516266077Sdes dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; 517266077Sdes 518266077Sdes /* ........ .......3 3333.... ........ ........ */ 519266077Sdes /* ........ ........ ....4444 4....... ........ */ 520266077Sdes dst[2] = buf[3] << 4 | buf[4] >> 1; 521266077Sdes 522266077Sdes /* ........ ........ ....4444 4....... ........ */ 523266077Sdes /* ........ ........ ........ .55555.. ........ */ 524266077Sdes /* ........ ........ ........ ......66 666..... */ 525266077Sdes dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; 526266077Sdes 527266077Sdes /* ........ ........ ........ ......66 666..... */ 528266077Sdes /* ........ ........ ........ ........ ...77777 */ 529266077Sdes dst[4] = buf[6] << 5 | buf[7]; 530266077Sdes 531266077Sdes dst += 5; 532266077Sdes dst_sz -= 5; 533266077Sdes } 534266077Sdes /* Not ending on a eight byte boundary? */ 535266077Sdes if (i > 0 && i < 8) { 536266077Sdes 537266077Sdes /* Enough space available at the destination? */ 538266077Sdes if (dst_sz < (i + 1) / 2) 539266077Sdes return -1; 540266077Sdes 541266077Sdes switch (i) { 542266077Sdes case 7: /* ........ ........ ........ ......66 666..... */ 543266077Sdes /* ........ ........ ........ .55555.. ........ */ 544266077Sdes /* ........ ........ ....4444 4....... ........ */ 545266077Sdes dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3; 546356345Scy /* fallthrough */ 547266077Sdes 548266077Sdes case 5: /* ........ ........ ....4444 4....... ........ */ 549266077Sdes /* ........ .......3 3333.... ........ ........ */ 550266077Sdes dst[2] = buf[3] << 4 | buf[4] >> 1; 551356345Scy /* fallthrough */ 552266077Sdes 553266077Sdes case 4: /* ........ .......3 3333.... ........ ........ */ 554266077Sdes /* ........ ..22222. ........ ........ ........ */ 555266077Sdes /* .....111 11...... ........ ........ ........ */ 556266077Sdes dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4; 557356345Scy /* fallthrough */ 558266077Sdes 559266077Sdes case 2: /* .....111 11...... ........ ........ ........ */ 560266077Sdes /* 00000... ........ ........ ........ ........ */ 561266077Sdes dst[0] = buf[0] << 3 | buf[1] >> 2; 562266077Sdes 563266077Sdes break; 564266077Sdes 565266077Sdes default: 566266077Sdes return -1; 567266077Sdes } 568266077Sdes dst += (i + 1) / 2; 569266077Sdes 570266077Sdes if (check_padding) { 571266077Sdes /* Check remaining padding characters */ 572266077Sdes if (ch != '=') 573266077Sdes return -1; 574266077Sdes 575266077Sdes /* One down, 8 - i - 1 more to come... */ 576266077Sdes for (i = 8 - i - 1; i > 0; i--) { 577266077Sdes 578266077Sdes do { 579266077Sdes if (src_sz == 0) 580266077Sdes return -1; 581266077Sdes ch = *src++; 582266077Sdes src_sz--; 583266077Sdes 584276541Sdes } while (isspace((unsigned char)ch)); 585266077Sdes 586266077Sdes if (ch != '=') 587266077Sdes return -1; 588266077Sdes } 589266077Sdes } 590266077Sdes } 591266077Sdes return dst - start; 592266077Sdes} 593266077Sdes 594266077Sdesint 595266077Sdessldns_b32_pton(const char* src, size_t src_sz, uint8_t* dst, size_t dst_sz) 596266077Sdes{ 597266077Sdes return sldns_b32_pton_base(src, src_sz, dst, dst_sz, 0, 1); 598266077Sdes} 599266077Sdes 600266077Sdesint 601266077Sdessldns_b32_pton_extended_hex(const char* src, size_t src_sz, 602266077Sdes uint8_t* dst, size_t dst_sz) 603266077Sdes{ 604266077Sdes return sldns_b32_pton_base(src, src_sz, dst, dst_sz, 1, 1); 605266077Sdes} 606266077Sdes 607266077Sdessize_t sldns_b64_ntop_calculate_size(size_t srcsize) 608266077Sdes{ 609266077Sdes return ((((srcsize + 2) / 3) * 4) + 1); 610266077Sdes} 611266077Sdes 612266077Sdes/* RFC 1521, section 5.2. 613266077Sdes * 614266077Sdes * The encoding process represents 24-bit groups of input bits as output 615266077Sdes * strings of 4 encoded characters. Proceeding from left to right, a 616266077Sdes * 24-bit input group is formed by concatenating 3 8-bit input groups. 617266077Sdes * These 24 bits are then treated as 4 concatenated 6-bit groups, each 618266077Sdes * of which is translated into a single digit in the base64 alphabet. 619266077Sdes * 620266077Sdes * This routine does not insert spaces or linebreaks after 76 characters. 621266077Sdes */ 622368129Scystatic int sldns_b64_ntop_base(uint8_t const *src, size_t srclength, 623368129Scy char *target, size_t targsize, int base64url, int padding) 624266077Sdes{ 625368129Scy char* b64; 626266077Sdes const char pad64 = '='; 627266077Sdes size_t i = 0, o = 0; 628368129Scy if(base64url) 629368129Scy b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123" 630368129Scy "456789-_"; 631368129Scy else 632368129Scy b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123" 633368129Scy "456789+/"; 634266077Sdes if(targsize < sldns_b64_ntop_calculate_size(srclength)) 635266077Sdes return -1; 636266077Sdes /* whole chunks: xxxxxxyy yyyyzzzz zzwwwwww */ 637266077Sdes while(i+3 <= srclength) { 638266077Sdes if(o+4 > targsize) return -1; 639266077Sdes target[o] = b64[src[i] >> 2]; 640266077Sdes target[o+1] = b64[ ((src[i]&0x03)<<4) | (src[i+1]>>4) ]; 641266077Sdes target[o+2] = b64[ ((src[i+1]&0x0f)<<2) | (src[i+2]>>6) ]; 642266077Sdes target[o+3] = b64[ (src[i+2]&0x3f) ]; 643266077Sdes i += 3; 644266077Sdes o += 4; 645266077Sdes } 646266077Sdes /* remainder */ 647266077Sdes switch(srclength - i) { 648266077Sdes case 2: 649266077Sdes /* two at end, converted into A B C = */ 650266077Sdes target[o] = b64[src[i] >> 2]; 651266077Sdes target[o+1] = b64[ ((src[i]&0x03)<<4) | (src[i+1]>>4) ]; 652266077Sdes target[o+2] = b64[ ((src[i+1]&0x0f)<<2) ]; 653368129Scy if(padding) { 654368129Scy target[o+3] = pad64; 655368129Scy /* i += 2; */ 656368129Scy o += 4; 657368129Scy } else { 658368129Scy o += 3; 659368129Scy } 660266077Sdes break; 661266077Sdes case 1: 662266077Sdes /* one at end, converted into A B = = */ 663266077Sdes target[o] = b64[src[i] >> 2]; 664266077Sdes target[o+1] = b64[ ((src[i]&0x03)<<4) ]; 665368129Scy if(padding) { 666368129Scy target[o+2] = pad64; 667368129Scy target[o+3] = pad64; 668368129Scy /* i += 1; */ 669368129Scy o += 4; 670368129Scy } else { 671368129Scy o += 2; 672368129Scy } 673266077Sdes break; 674266077Sdes case 0: 675266077Sdes default: 676266077Sdes /* nothing */ 677266077Sdes break; 678266077Sdes } 679266077Sdes /* assert: i == srclength */ 680266077Sdes if(o+1 > targsize) return -1; 681266077Sdes target[o] = 0; 682266077Sdes return (int)o; 683266077Sdes} 684266077Sdes 685368129Scyint sldns_b64_ntop(uint8_t const *src, size_t srclength, char *target, 686368129Scy size_t targsize) 687368129Scy{ 688368129Scy return sldns_b64_ntop_base(src, srclength, target, targsize, 689368129Scy 0 /* no base64url */, 1 /* padding */); 690368129Scy} 691368129Scy 692368129Scyint sldns_b64url_ntop(uint8_t const *src, size_t srclength, char *target, 693368129Scy size_t targsize) 694368129Scy{ 695368129Scy return sldns_b64_ntop_base(src, srclength, target, targsize, 696368129Scy 1 /* base64url */, 0 /* no padding */); 697368129Scy} 698368129Scy 699266077Sdessize_t sldns_b64_pton_calculate_size(size_t srcsize) 700266077Sdes{ 701266077Sdes return (((((srcsize + 3) / 4) * 3)) + 1); 702266077Sdes} 703266077Sdes 704368129Scy/* padding not required if srcsize is set */ 705368129Scystatic int sldns_b64_pton_base(char const *src, size_t srcsize, uint8_t *target, 706368129Scy size_t targsize, int base64url) 707266077Sdes{ 708266077Sdes const uint8_t pad64 = 64; /* is 64th in the b64 array */ 709266077Sdes const char* s = src; 710266077Sdes uint8_t in[4]; 711266077Sdes size_t o = 0, incount = 0; 712368129Scy int check_padding = (srcsize) ? 0 : 1; 713266077Sdes 714368129Scy while(*s && (check_padding || srcsize)) { 715266077Sdes /* skip any character that is not base64 */ 716266077Sdes /* conceptually we do: 717266077Sdes const char* b64 = pad'=' is appended to array 718266077Sdes "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 719266077Sdes const char* d = strchr(b64, *s++); 720266077Sdes and use d-b64; 721266077Sdes */ 722266077Sdes char d = *s++; 723368129Scy srcsize--; 724266077Sdes if(d <= 'Z' && d >= 'A') 725266077Sdes d -= 'A'; 726266077Sdes else if(d <= 'z' && d >= 'a') 727266077Sdes d = d - 'a' + 26; 728266077Sdes else if(d <= '9' && d >= '0') 729266077Sdes d = d - '0' + 52; 730368129Scy else if(!base64url && d == '+') 731266077Sdes d = 62; 732368129Scy else if(base64url && d == '-') 733368129Scy d = 62; 734368129Scy else if(!base64url && d == '/') 735266077Sdes d = 63; 736368129Scy else if(base64url && d == '_') 737368129Scy d = 63; 738368129Scy else if(d == '=') { 739368129Scy if(!check_padding) 740368129Scy continue; 741266077Sdes d = 64; 742368129Scy } else continue; 743368129Scy 744266077Sdes in[incount++] = (uint8_t)d; 745368129Scy /* work on block of 4, unless padding is not used and there are 746368129Scy * less than 4 chars left */ 747368129Scy if(incount != 4 && (check_padding || srcsize)) 748266077Sdes continue; 749368129Scy assert(!check_padding || incount==4); 750266077Sdes /* process whole block of 4 characters into 3 output bytes */ 751368129Scy if((incount == 2 || 752368129Scy (incount == 4 && in[3] == pad64 && in[2] == pad64))) { /* A B = = */ 753266077Sdes if(o+1 > targsize) 754266077Sdes return -1; 755266077Sdes target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); 756266077Sdes o += 1; 757266077Sdes break; /* we are done */ 758368129Scy } else if(incount == 3 || 759368129Scy (incount == 4 && in[3] == pad64)) { /* A B C = */ 760266077Sdes if(o+2 > targsize) 761266077Sdes return -1; 762266077Sdes target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); 763266077Sdes target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2); 764266077Sdes o += 2; 765266077Sdes break; /* we are done */ 766266077Sdes } else { 767368129Scy if(incount != 4 || o+3 > targsize) 768266077Sdes return -1; 769266077Sdes /* write xxxxxxyy yyyyzzzz zzwwwwww */ 770266077Sdes target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); 771266077Sdes target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2); 772266077Sdes target[o+2]= ((in[2]&0x03)<<6) | in[3]; 773266077Sdes o += 3; 774266077Sdes } 775266077Sdes incount = 0; 776266077Sdes } 777266077Sdes return (int)o; 778266077Sdes} 779368129Scy 780368129Scyint sldns_b64_pton(char const *src, uint8_t *target, size_t targsize) 781368129Scy{ 782368129Scy return sldns_b64_pton_base(src, 0, target, targsize, 0); 783368129Scy} 784368129Scy 785368129Scyint sldns_b64url_pton(char const *src, size_t srcsize, uint8_t *target, 786368129Scy size_t targsize) 787368129Scy{ 788368129Scy if(!srcsize) { 789368129Scy return 0; 790368129Scy } 791368129Scy return sldns_b64_pton_base(src, srcsize, target, targsize, 1); 792368129Scy} 793