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