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