Coverage Report

Created: 2022-03-10 07:56

/src/bind9/lib/isc/base64.c
Line
Count
Source (jump to first uncovered line)
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/base64.h>
19
#include <isc/buffer.h>
20
#include <isc/lex.h>
21
#include <isc/string.h>
22
#include <isc/util.h>
23
24
#define RETERR(x)                        \
25
4.32M
  do {                             \
26
4.32M
    isc_result_t _r = (x);   \
27
4.32M
    if (_r != ISC_R_SUCCESS) \
28
4.32M
      return ((_r));   \
29
4.32M
  } while (0)
30
31
/*@{*/
32
/*!
33
 * These static functions are also present in lib/dns/rdata.c.  I'm not
34
 * sure where they should go. -- bwelling
35
 */
36
static isc_result_t
37
str_totext(const char *source, isc_buffer_t *target);
38
39
static isc_result_t
40
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
41
42
static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvw"
43
           "xyz0123456789+/=";
44
/*@}*/
45
46
isc_result_t
47
isc_base64_totext(isc_region_t *source, int wordlength, const char *wordbreak,
48
69.0k
      isc_buffer_t *target) {
49
69.0k
  char buf[5];
50
69.0k
  unsigned int loops = 0;
51
52
69.0k
  if (wordlength < 4) {
53
13.3k
    wordlength = 4;
54
13.3k
  }
55
56
69.0k
  memset(buf, 0, sizeof(buf));
57
1.04M
  while (source->length > 2) {
58
979k
    buf[0] = base64[(source->base[0] >> 2) & 0x3f];
59
979k
    buf[1] = base64[((source->base[0] << 4) & 0x30) |
60
979k
        ((source->base[1] >> 4) & 0x0f)];
61
979k
    buf[2] = base64[((source->base[1] << 2) & 0x3c) |
62
979k
        ((source->base[2] >> 6) & 0x03)];
63
979k
    buf[3] = base64[source->base[2] & 0x3f];
64
979k
    RETERR(str_totext(buf, target));
65
979k
    isc_region_consume(source, 3);
66
67
0
    loops++;
68
979k
    if (source->length != 0 && (int)((loops + 1) * 4) >= wordlength)
69
219k
    {
70
219k
      loops = 0;
71
219k
      RETERR(str_totext(wordbreak, target));
72
219k
    }
73
979k
  }
74
69.0k
  if (source->length == 2) {
75
15.5k
    buf[0] = base64[(source->base[0] >> 2) & 0x3f];
76
15.5k
    buf[1] = base64[((source->base[0] << 4) & 0x30) |
77
15.5k
        ((source->base[1] >> 4) & 0x0f)];
78
15.5k
    buf[2] = base64[((source->base[1] << 2) & 0x3c)];
79
15.5k
    buf[3] = '=';
80
15.5k
    RETERR(str_totext(buf, target));
81
15.5k
    isc_region_consume(source, 2);
82
53.4k
  } else if (source->length == 1) {
83
39.4k
    buf[0] = base64[(source->base[0] >> 2) & 0x3f];
84
39.4k
    buf[1] = base64[((source->base[0] << 4) & 0x30)];
85
39.4k
    buf[2] = buf[3] = '=';
86
39.4k
    RETERR(str_totext(buf, target));
87
39.4k
    isc_region_consume(source, 1);
88
39.4k
  }
89
69.0k
  return (ISC_R_SUCCESS);
90
69.0k
}
91
92
/*%
93
 * State of a base64 decoding process in progress.
94
 */
95
typedef struct {
96
  int length;       /*%< Desired length of binary data or -1 */
97
  isc_buffer_t *target; /*%< Buffer for resulting binary data */
98
  int digits;       /*%< Number of buffered base64 digits */
99
  bool seen_end;        /*%< True if "=" end marker seen */
100
  int val[4];
101
} base64_decode_ctx_t;
102
103
static inline void
104
38.3k
base64_decode_init(base64_decode_ctx_t *ctx, int length, isc_buffer_t *target) {
105
38.3k
  ctx->digits = 0;
106
38.3k
  ctx->seen_end = false;
107
38.3k
  ctx->length = length;
108
38.3k
  ctx->target = target;
109
38.3k
}
110
111
static inline isc_result_t
112
2.32M
base64_decode_char(base64_decode_ctx_t *ctx, int c) {
113
2.32M
  const char *s;
114
115
2.32M
  if (ctx->seen_end) {
116
6
    return (ISC_R_BADBASE64);
117
6
  }
118
2.32M
  if ((s = strchr(base64, c)) == NULL) {
119
123
    return (ISC_R_BADBASE64);
120
123
  }
121
2.32M
  ctx->val[ctx->digits++] = (int)(s - base64);
122
2.32M
  if (ctx->digits == 4) {
123
582k
    int n;
124
582k
    unsigned char buf[3];
125
582k
    if (ctx->val[0] == 64 || ctx->val[1] == 64) {
126
4
      return (ISC_R_BADBASE64);
127
4
    }
128
582k
    if (ctx->val[2] == 64 && ctx->val[3] != 64) {
129
12
      return (ISC_R_BADBASE64);
130
12
    }
131
    /*
132
     * Check that bits that should be zero are.
133
     */
134
582k
    if (ctx->val[2] == 64 && (ctx->val[1] & 0xf) != 0) {
135
2
      return (ISC_R_BADBASE64);
136
2
    }
137
    /*
138
     * We don't need to test for ctx->val[2] != 64 as
139
     * the bottom two bits of 64 are zero.
140
     */
141
582k
    if (ctx->val[3] == 64 && (ctx->val[2] & 0x3) != 0) {
142
1
      return (ISC_R_BADBASE64);
143
1
    }
144
582k
    n = (ctx->val[2] == 64) ? 1 : (ctx->val[3] == 64) ? 2 : 3;
145
582k
    if (n != 3) {
146
2.18k
      ctx->seen_end = true;
147
2.18k
      if (ctx->val[2] == 64) {
148
1.57k
        ctx->val[2] = 0;
149
1.57k
      }
150
2.18k
      if (ctx->val[3] == 64) {
151
2.18k
        ctx->val[3] = 0;
152
2.18k
      }
153
2.18k
    }
154
582k
    buf[0] = (ctx->val[0] << 2) | (ctx->val[1] >> 4);
155
582k
    buf[1] = (ctx->val[1] << 4) | (ctx->val[2] >> 2);
156
582k
    buf[2] = (ctx->val[2] << 6) | (ctx->val[3]);
157
582k
    RETERR(mem_tobuffer(ctx->target, buf, n));
158
582k
    if (ctx->length >= 0) {
159
464
      if (n > ctx->length) {
160
2
        return (ISC_R_BADBASE64);
161
462
      } else {
162
462
        ctx->length -= n;
163
462
      }
164
464
    }
165
582k
    ctx->digits = 0;
166
582k
  }
167
2.32M
  return (ISC_R_SUCCESS);
168
2.32M
}
169
170
static inline isc_result_t
171
38.1k
base64_decode_finish(base64_decode_ctx_t *ctx) {
172
38.1k
  if (ctx->length > 0) {
173
12
    return (ISC_R_UNEXPECTEDEND);
174
12
  }
175
38.1k
  if (ctx->digits != 0) {
176
61
    return (ISC_R_BADBASE64);
177
61
  }
178
38.0k
  return (ISC_R_SUCCESS);
179
38.1k
}
180
181
isc_result_t
182
27.5k
isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
183
27.5k
  unsigned int before, after;
184
27.5k
  base64_decode_ctx_t ctx;
185
27.5k
  isc_textregion_t *tr;
186
27.5k
  isc_token_t token;
187
27.5k
  bool eol;
188
189
27.5k
  REQUIRE(length >= -2);
190
191
0
  base64_decode_init(&ctx, length, target);
192
193
27.5k
  before = isc_buffer_usedlength(target);
194
126k
  while (!ctx.seen_end && (ctx.length != 0)) {
195
124k
    unsigned int i;
196
197
124k
    if (length > 0) {
198
418
      eol = false;
199
124k
    } else {
200
124k
      eol = true;
201
124k
    }
202
124k
    RETERR(isc_lex_getmastertoken(lexer, &token,
203
124k
                isc_tokentype_string, eol));
204
124k
    if (token.type != isc_tokentype_string) {
205
25.5k
      break;
206
25.5k
    }
207
98.8k
    tr = &token.value.as_textregion;
208
1.16M
    for (i = 0; i < tr->length; i++) {
209
1.06M
      RETERR(base64_decode_char(&ctx, tr->base[i]));
210
1.06M
    }
211
98.8k
  }
212
27.3k
  after = isc_buffer_usedlength(target);
213
27.3k
  if (ctx.length < 0 && !ctx.seen_end) {
214
25.5k
    isc_lex_ungettoken(lexer, &token);
215
25.5k
  }
216
27.3k
  RETERR(base64_decode_finish(&ctx));
217
27.2k
  if (length == -2 && before == after) {
218
33
    return (ISC_R_UNEXPECTEDEND);
219
33
  }
220
27.2k
  return (ISC_R_SUCCESS);
221
27.2k
}
222
223
isc_result_t
224
10.8k
isc_base64_decodestring(const char *cstr, isc_buffer_t *target) {
225
10.8k
  base64_decode_ctx_t ctx;
226
227
10.8k
  base64_decode_init(&ctx, -1, target);
228
1.27M
  for (;;) {
229
1.27M
    int c = *cstr++;
230
1.27M
    if (c == '\0') {
231
10.8k
      break;
232
10.8k
    }
233
1.26M
    if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
234
1.26k
      continue;
235
1.26k
    }
236
1.26M
    RETERR(base64_decode_char(&ctx, c));
237
1.26M
  }
238
10.8k
  RETERR(base64_decode_finish(&ctx));
239
10.7k
  return (ISC_R_SUCCESS);
240
10.8k
}
241
242
static isc_result_t
243
1.25M
str_totext(const char *source, isc_buffer_t *target) {
244
1.25M
  unsigned int l;
245
1.25M
  isc_region_t region;
246
247
1.25M
  isc_buffer_availableregion(target, &region);
248
1.25M
  l = strlen(source);
249
250
1.25M
  if (l > region.length) {
251
0
    return (ISC_R_NOSPACE);
252
0
  }
253
254
1.25M
  memmove(region.base, source, l);
255
1.25M
  isc_buffer_add(target, l);
256
1.25M
  return (ISC_R_SUCCESS);
257
1.25M
}
258
259
static isc_result_t
260
582k
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
261
582k
  isc_region_t tr;
262
263
582k
  isc_buffer_availableregion(target, &tr);
264
582k
  if (length > tr.length) {
265
3
    return (ISC_R_NOSPACE);
266
3
  }
267
582k
  memmove(tr.base, base, length);
268
582k
  isc_buffer_add(target, length);
269
582k
  return (ISC_R_SUCCESS);
270
582k
}