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
21sldns_lookup_table *
22sldns_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
32sldns_lookup_table *
33sldns_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). */
44static 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
51static int
52is_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
58static int
59leap_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 */
71time_t
72sldns_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
98static void
99sldns_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. */
115static const int leap_year_mdays[] = {
116	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
117};
118
119static void
120sldns_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
133static void
134sldns_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
146static struct tm *
147sldns_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
167static int64_t
168sldns_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
174struct tm *
175sldns_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
186int
187sldns_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
211uint32_t
212sldns_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
320int
321sldns_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	}
345error:
346	*str_p = NULL;
347	return 0; /* LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE */
348}
349
350/** parse one character, with escape codes */
351int
352sldns_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
366size_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
371size_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
376static int
377sldns_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
475int
476sldns_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
481int
482sldns_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
488size_t sldns_b32_pton_calculate_size(size_t src_text_length)
489{
490	return src_text_length * 5 / 8;
491}
492
493static int
494sldns_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
628int
629sldns_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
634int
635sldns_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
641size_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 */
656static 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
719int 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
726int 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
733size_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 */
739static 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
814int 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
819int 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
828int 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