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