Coverage Report

Created: 2025-07-11 06:08

/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
}