Coverage Report

Created: 2025-12-14 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/base32.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <stdbool.h>
17
18
#include <isc/base32.h>
19
#include <isc/buffer.h>
20
#include <isc/lex.h>
21
#include <isc/region.h>
22
#include <isc/string.h>
23
#include <isc/util.h>
24
25
/*@{*/
26
/*!
27
 * These static functions are also present in lib/dns/rdata.c.  I'm not
28
 * sure where they should go. -- bwelling
29
 */
30
static isc_result_t
31
str_totext(const char *source, isc_buffer_t *target);
32
33
static isc_result_t
34
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
35
36
/*@}*/
37
38
static const char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567="
39
           "abcdefghijklmnopqrstuvwxyz234567";
40
static const char base32hex[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV="
41
        "0123456789abcdefghijklmnopqrstuv";
42
43
static isc_result_t
44
base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
45
4.74k
        isc_buffer_t *target, const char base[], char pad) {
46
4.74k
  char buf[9];
47
4.74k
  unsigned int loops = 0;
48
49
4.74k
  if (wordlength >= 0 && wordlength < 8) {
50
4.74k
    wordlength = 8;
51
4.74k
  }
52
53
4.74k
  memset(buf, 0, sizeof(buf));
54
12.8k
  while (source->length > 0) {
55
11.0k
    buf[0] = base[((source->base[0] >> 3) & 0x1f)]; /* 5 + */
56
11.0k
    if (source->length == 1) {
57
510
      buf[1] = base[(source->base[0] << 2) & 0x1c];
58
510
      buf[2] = buf[3] = buf[4] = pad;
59
510
      buf[5] = buf[6] = buf[7] = pad;
60
510
      RETERR(str_totext(buf, target));
61
510
      break;
62
510
    }
63
10.5k
    buf[1] = base[((source->base[0] << 2) & 0x1c) | /* 3 = 8 */
64
10.5k
            ((source->base[1] >> 6) & 0x03)]; /* 2 + */
65
10.5k
    buf[2] = base[((source->base[1] >> 1) & 0x1f)]; /* 5 + */
66
10.5k
    if (source->length == 2) {
67
1.31k
      buf[3] = base[(source->base[1] << 4) & 0x10];
68
1.31k
      buf[4] = buf[5] = buf[6] = buf[7] = pad;
69
1.31k
      RETERR(str_totext(buf, target));
70
1.31k
      break;
71
1.31k
    }
72
9.27k
    buf[3] = base[((source->base[1] << 4) & 0x10) | /* 1 = 8 */
73
9.27k
            ((source->base[2] >> 4) & 0x0f)]; /* 4 + */
74
9.27k
    if (source->length == 3) {
75
164
      buf[4] = base[(source->base[2] << 1) & 0x1e];
76
164
      buf[5] = buf[6] = buf[7] = pad;
77
164
      RETERR(str_totext(buf, target));
78
164
      break;
79
164
    }
80
9.11k
    buf[4] = base[((source->base[2] << 1) & 0x1e) | /* 4 = 8 */
81
9.11k
            ((source->base[3] >> 7) & 0x01)]; /* 1 + */
82
9.11k
    buf[5] = base[((source->base[3] >> 2) & 0x1f)]; /* 5 + */
83
9.11k
    if (source->length == 4) {
84
978
      buf[6] = base[(source->base[3] << 3) & 0x18];
85
978
      buf[7] = pad;
86
978
      RETERR(str_totext(buf, target));
87
978
      break;
88
978
    }
89
8.13k
    buf[6] = base[((source->base[3] << 3) & 0x18) | /* 2 = 8 */
90
8.13k
            ((source->base[4] >> 5) & 0x07)]; /* 3 + */
91
8.13k
    buf[7] = base[source->base[4] & 0x1f];    /* 5 = 8 */
92
8.13k
    RETERR(str_totext(buf, target));
93
8.13k
    isc_region_consume(source, 5);
94
95
8.13k
    loops++;
96
8.13k
    if (source->length != 0 && wordlength >= 0 &&
97
6.35k
        (int)((loops + 1) * 8) >= wordlength)
98
6.35k
    {
99
6.35k
      loops = 0;
100
6.35k
      RETERR(str_totext(wordbreak, target));
101
6.35k
    }
102
8.13k
  }
103
4.74k
  if (source->length > 0) {
104
2.96k
    isc_region_consume(source, source->length);
105
2.96k
  }
106
4.74k
  return ISC_R_SUCCESS;
107
4.74k
}
108
109
isc_result_t
110
isc_base32_totext(isc_region_t *source, int wordlength, const char *wordbreak,
111
0
      isc_buffer_t *target) {
112
0
  return base32_totext(source, wordlength, wordbreak, target, base32,
113
0
           '=');
114
0
}
115
116
isc_result_t
117
isc_base32hex_totext(isc_region_t *source, int wordlength,
118
0
         const char *wordbreak, isc_buffer_t *target) {
119
0
  return base32_totext(source, wordlength, wordbreak, target, base32hex,
120
0
           '=');
121
0
}
122
123
isc_result_t
124
isc_base32hexnp_totext(isc_region_t *source, int wordlength,
125
4.74k
           const char *wordbreak, isc_buffer_t *target) {
126
4.74k
  return base32_totext(source, wordlength, wordbreak, target, base32hex,
127
4.74k
           0);
128
4.74k
}
129
130
/*%
131
 * State of a base32 decoding process in progress.
132
 */
133
typedef struct {
134
  int length;       /*%< Desired length of binary data or -1 */
135
  isc_buffer_t *target; /*%< Buffer for resulting binary data */
136
  int digits;       /*%< Number of buffered base32 digits */
137
  bool seen_end;        /*%< True if "=" end marker seen */
138
  int val[8];
139
  const char *base; /*%< Which encoding we are using */
140
  int seen_32;    /*%< Number of significant bytes if non
141
         * zero */
142
  bool pad;   /*%< Expect padding */
143
} base32_decode_ctx_t;
144
145
static isc_result_t
146
118k
base32_decode_char(base32_decode_ctx_t *ctx, int c) {
147
118k
  const char *s;
148
118k
  unsigned int last;
149
150
118k
  if (ctx->seen_end) {
151
0
    return ISC_R_BADBASE32;
152
0
  }
153
118k
  if ((s = strchr(ctx->base, c)) == NULL) {
154
26
    return ISC_R_BADBASE32;
155
26
  }
156
118k
  last = (unsigned int)(s - ctx->base);
157
158
  /*
159
   * Handle lower case.
160
   */
161
118k
  if (last > 32) {
162
7.93k
    last -= 33;
163
7.93k
  }
164
165
  /*
166
   * Check that padding is contiguous.
167
   */
168
118k
  if (last != 32 && ctx->seen_32 != 0) {
169
0
    return ISC_R_BADBASE32;
170
0
  }
171
172
  /*
173
   * If padding is not permitted flag padding as a error.
174
   */
175
118k
  if (last == 32 && !ctx->pad) {
176
4
    return ISC_R_BADBASE32;
177
4
  }
178
179
  /*
180
   * Check that padding starts at the right place and that
181
   * bits that should be zero are.
182
   * Record how many significant bytes in answer (seen_32).
183
   */
184
117k
  if (last == 32 && ctx->seen_32 == 0) {
185
3.75k
    switch (ctx->digits) {
186
0
    case 0:
187
13
    case 1:
188
13
      return ISC_R_BADBASE32;
189
2.06k
    case 2:
190
2.06k
      if ((ctx->val[1] & 0x03) != 0) {
191
9
        return ISC_R_BADBASE32;
192
9
      }
193
2.05k
      ctx->seen_32 = 1;
194
2.05k
      break;
195
5
    case 3:
196
5
      return ISC_R_BADBASE32;
197
634
    case 4:
198
634
      if ((ctx->val[3] & 0x0f) != 0) {
199
5
        return ISC_R_BADBASE32;
200
5
      }
201
629
      ctx->seen_32 = 2;
202
629
      break;
203
790
    case 5:
204
790
      if ((ctx->val[4] & 0x01) != 0) {
205
3
        return ISC_R_BADBASE32;
206
3
      }
207
787
      ctx->seen_32 = 3;
208
787
      break;
209
4
    case 6:
210
4
      return ISC_R_BADBASE32;
211
244
    case 7:
212
244
      if ((ctx->val[6] & 0x07) != 0) {
213
4
        return ISC_R_BADBASE32;
214
4
      }
215
240
      ctx->seen_32 = 4;
216
240
      break;
217
3.75k
    }
218
3.75k
  }
219
220
  /*
221
   * Zero fill pad values.
222
   */
223
117k
  ctx->val[ctx->digits++] = (last == 32) ? 0 : last;
224
225
117k
  if (ctx->digits == 8) {
226
14.7k
    int n = 5;
227
14.7k
    unsigned char buf[5];
228
229
14.7k
    if (ctx->seen_32 != 0) {
230
3.71k
      ctx->seen_end = true;
231
3.71k
      n = ctx->seen_32;
232
3.71k
    }
233
14.7k
    buf[0] = (ctx->val[0] << 3) | (ctx->val[1] >> 2);
234
14.7k
    buf[1] = (ctx->val[1] << 6) | (ctx->val[2] << 1) |
235
14.7k
       (ctx->val[3] >> 4);
236
14.7k
    buf[2] = (ctx->val[3] << 4) | (ctx->val[4] >> 1);
237
14.7k
    buf[3] = (ctx->val[4] << 7) | (ctx->val[5] << 2) |
238
14.7k
       (ctx->val[6] >> 3);
239
14.7k
    buf[4] = (ctx->val[6] << 5) | (ctx->val[7]);
240
14.7k
    RETERR(mem_tobuffer(ctx->target, buf, n));
241
14.7k
    if (ctx->length >= 0) {
242
0
      if (n > ctx->length) {
243
0
        return ISC_R_BADBASE32;
244
0
      } else {
245
0
        ctx->length -= n;
246
0
      }
247
0
    }
248
14.7k
    ctx->digits = 0;
249
14.7k
  }
250
117k
  return ISC_R_SUCCESS;
251
117k
}
252
253
static isc_result_t
254
8.90k
base32_decode_finish(base32_decode_ctx_t *ctx) {
255
8.90k
  if (ctx->length > 0) {
256
0
    return ISC_R_UNEXPECTEDEND;
257
0
  }
258
  /*
259
   * Add missing padding if required.
260
   */
261
8.90k
  if (!ctx->pad && ctx->digits != 0) {
262
3.75k
    ctx->pad = true;
263
17.5k
    do {
264
17.5k
      RETERR(base32_decode_char(ctx, '='));
265
17.4k
    } while (ctx->digits != 0);
266
3.75k
  }
267
8.85k
  if (ctx->digits != 0) {
268
0
    return ISC_R_BADBASE32;
269
0
  }
270
8.85k
  return ISC_R_SUCCESS;
271
8.85k
}
272
273
static isc_result_t
274
base32_tobuffer(isc_lex_t *lexer, const char base[], bool pad,
275
0
    isc_buffer_t *target, int length) {
276
0
  unsigned int before, after;
277
0
  base32_decode_ctx_t ctx = {
278
0
    .length = length, .base = base, .target = target, .pad = pad
279
0
  };
280
0
  isc_textregion_t *tr;
281
0
  isc_token_t token;
282
0
  bool eol;
283
284
0
  REQUIRE(length >= -2);
285
286
0
  before = isc_buffer_usedlength(target);
287
0
  while (!ctx.seen_end && (ctx.length != 0)) {
288
0
    unsigned int i;
289
290
0
    if (length > 0) {
291
0
      eol = false;
292
0
    } else {
293
0
      eol = true;
294
0
    }
295
0
    RETERR(isc_lex_getmastertoken(lexer, &token,
296
0
                isc_tokentype_string, eol));
297
0
    if (token.type != isc_tokentype_string) {
298
0
      break;
299
0
    }
300
0
    tr = &token.value.as_textregion;
301
0
    for (i = 0; i < tr->length; i++) {
302
0
      RETERR(base32_decode_char(&ctx, tr->base[i]));
303
0
    }
304
0
  }
305
0
  after = isc_buffer_usedlength(target);
306
0
  if (ctx.length < 0 && !ctx.seen_end) {
307
0
    isc_lex_ungettoken(lexer, &token);
308
0
  }
309
0
  RETERR(base32_decode_finish(&ctx));
310
0
  if (length == -2 && before == after) {
311
0
    return ISC_R_UNEXPECTEDEND;
312
0
  }
313
0
  return ISC_R_SUCCESS;
314
0
}
315
316
isc_result_t
317
0
isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
318
0
  return base32_tobuffer(lexer, base32, true, target, length);
319
0
}
320
321
isc_result_t
322
0
isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
323
0
  return base32_tobuffer(lexer, base32hex, true, target, length);
324
0
}
325
326
isc_result_t
327
0
isc_base32hexnp_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
328
0
  return base32_tobuffer(lexer, base32hex, false, target, length);
329
0
}
330
331
static isc_result_t
332
base32_decodestring(const char *cstr, const char base[], bool pad,
333
2.92k
        isc_buffer_t *target) {
334
2.92k
  base32_decode_ctx_t ctx = {
335
2.92k
    .length = -1, .base = base, .target = target, .pad = pad
336
2.92k
  };
337
338
30.2k
  for (;;) {
339
30.2k
    int c = *cstr++;
340
30.2k
    if (c == '\0') {
341
2.90k
      break;
342
2.90k
    }
343
27.3k
    if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
344
0
      continue;
345
0
    }
346
27.3k
    RETERR(base32_decode_char(&ctx, c));
347
27.3k
  }
348
2.90k
  RETERR(base32_decode_finish(&ctx));
349
2.86k
  return ISC_R_SUCCESS;
350
2.90k
}
351
352
isc_result_t
353
0
isc_base32_decodestring(const char *cstr, isc_buffer_t *target) {
354
0
  return base32_decodestring(cstr, base32, true, target);
355
0
}
356
357
isc_result_t
358
0
isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target) {
359
0
  return base32_decodestring(cstr, base32hex, true, target);
360
0
}
361
362
isc_result_t
363
2.92k
isc_base32hexnp_decodestring(const char *cstr, isc_buffer_t *target) {
364
2.92k
  return base32_decodestring(cstr, base32hex, false, target);
365
2.92k
}
366
367
static isc_result_t
368
base32_decoderegion(isc_region_t *source, const char base[], bool pad,
369
6.00k
        isc_buffer_t *target) {
370
6.00k
  base32_decode_ctx_t ctx = {
371
6.00k
    .length = -1, .base = base, .target = target, .pad = pad
372
6.00k
  };
373
374
79.1k
  while (source->length != 0) {
375
73.1k
    int c = *source->base;
376
73.1k
    RETERR(base32_decode_char(&ctx, c));
377
73.1k
    isc_region_consume(source, 1);
378
73.1k
  }
379
6.00k
  RETERR(base32_decode_finish(&ctx));
380
5.99k
  return ISC_R_SUCCESS;
381
6.00k
}
382
383
isc_result_t
384
0
isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target) {
385
0
  return base32_decoderegion(source, base32, true, target);
386
0
}
387
388
isc_result_t
389
0
isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target) {
390
0
  return base32_decoderegion(source, base32hex, true, target);
391
0
}
392
393
isc_result_t
394
6.00k
isc_base32hexnp_decoderegion(isc_region_t *source, isc_buffer_t *target) {
395
6.00k
  return base32_decoderegion(source, base32hex, false, target);
396
6.00k
}
397
398
static isc_result_t
399
17.4k
str_totext(const char *source, isc_buffer_t *target) {
400
17.4k
  unsigned int l;
401
17.4k
  isc_region_t region;
402
403
17.4k
  isc_buffer_availableregion(target, &region);
404
17.4k
  l = strlen(source);
405
406
17.4k
  if (l > region.length) {
407
0
    return ISC_R_NOSPACE;
408
0
  }
409
410
17.4k
  memmove(region.base, source, l);
411
17.4k
  isc_buffer_add(target, l);
412
17.4k
  return ISC_R_SUCCESS;
413
17.4k
}
414
415
static isc_result_t
416
14.7k
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
417
14.7k
  isc_region_t tr;
418
419
14.7k
  isc_buffer_availableregion(target, &tr);
420
14.7k
  if (length > tr.length) {
421
4
    return ISC_R_NOSPACE;
422
4
  }
423
14.7k
  memmove(tr.base, base, length);
424
14.7k
  isc_buffer_add(target, length);
425
14.7k
  return ISC_R_SUCCESS;
426
14.7k
}