Coverage Report

Created: 2026-06-10 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/p11-kit/common/base64.c
Line
Count
Source
1
/*
2
 * Copyright (c) 1996, 1998 by Internet Software Consortium.
3
 *
4
 * Permission to use, copy, modify, and distribute this software for any
5
 * purpose with or without fee is hereby granted, provided that the above
6
 * copyright notice and this permission notice appear in all copies.
7
 *
8
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15
 * SOFTWARE.
16
 */
17
18
/*
19
 * Portions Copyright (c) 1995 by International Business Machines, Inc.
20
 *
21
 * International Business Machines, Inc. (hereinafter called IBM) grants
22
 * permission under its copyrights to use, copy, modify, and distribute this
23
 * Software with or without fee, provided that the above copyright notice and
24
 * all paragraphs of this notice appear in all copies, and that the name of IBM
25
 * not be used in connection with the marketing of any product incorporating
26
 * the Software or modifications thereof, without specific, written prior
27
 * permission.
28
 *
29
 * To the extent it has a right to do so, IBM grants an immunity from suit
30
 * under its patents, if any, for the use, sale or manufacture of products to
31
 * the extent that such products are used for performing Domain Name System
32
 * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
33
 * granted for any product per se or for any other function of any product.
34
 *
35
 * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
36
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
37
 * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
38
 * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
39
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
40
 * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
41
 */
42
43
#include "config.h"
44
45
#include "base64.h"
46
#include "debug.h"
47
48
#include <assert.h>
49
#include <ctype.h>
50
#include <limits.h>
51
#include <stdlib.h>
52
#include <string.h>
53
54
static const char Base64[] =
55
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
56
57
static const char Pad64 = '=';
58
59
/* skips all whitespace anywhere.
60
 converts characters, four at a time, starting at (or after)
61
 src from base - 64 numbers into three 8 bit bytes in the target area.
62
 it returns the number of data bytes stored at the target, or -1 on error.
63
 */
64
65
int
66
p11_b64_pton (const char *src,
67
              size_t length,
68
              unsigned char *target,
69
              size_t targsize)
70
19.5k
{
71
19.5k
  int tarindex, state, ch;
72
19.5k
  const char *pos;
73
19.5k
  const char *end;
74
75
19.5k
  state = 0;
76
19.5k
  tarindex = 0;
77
19.5k
  end = src + length;
78
79
  /* We can't rely on the null terminator */
80
19.5k
  #define next_char(src, end) \
81
11.7M
    (((src) == (end)) ? '\0': *(src)++)
82
83
11.7M
  while ((ch = next_char (src, end)) != '\0') {
84
11.7M
    if (isspace ((unsigned char) ch)) /* Skip whitespace anywhere. */
85
186k
      continue;
86
87
11.5M
    if (ch == Pad64)
88
10.1k
      break;
89
90
11.5M
    pos = strchr (Base64, ch);
91
11.5M
    if (pos == 0) /* A non-base64 character. */
92
3.66k
      return (-1);
93
94
11.5M
    switch (state) {
95
2.89M
    case 0:
96
2.89M
      if (target) {
97
2.89M
        if ((size_t)tarindex >= targsize)
98
0
          return (-1);
99
2.89M
        target[tarindex] = (pos - Base64) << 2;
100
2.89M
      }
101
2.89M
      state = 1;
102
2.89M
      break;
103
2.89M
    case 1:
104
2.89M
      return_val_if_fail (tarindex < INT_MAX, -1);
105
2.89M
      if (target) {
106
2.89M
        if ((size_t) tarindex + 1 >= targsize)
107
0
          return (-1);
108
2.89M
        target[tarindex] |= (pos - Base64) >> 4;
109
2.89M
        target[tarindex + 1] = ((pos - Base64) & 0x0f)
110
2.89M
                        << 4;
111
2.89M
      }
112
2.89M
      tarindex++;
113
2.89M
      state = 2;
114
2.89M
      break;
115
2.88M
    case 2:
116
2.88M
      return_val_if_fail (tarindex < INT_MAX, -1);
117
2.88M
      if (target) {
118
2.88M
        if ((size_t) tarindex + 1 >= targsize)
119
0
          return (-1);
120
2.88M
        target[tarindex] |= (pos - Base64) >> 2;
121
2.88M
        target[tarindex + 1] = ((pos - Base64) & 0x03)
122
2.88M
                        << 6;
123
2.88M
      }
124
2.88M
      tarindex++;
125
2.88M
      state = 3;
126
2.88M
      break;
127
2.88M
    case 3:
128
2.88M
      return_val_if_fail (tarindex < INT_MAX, -1);
129
2.88M
      if (target) {
130
2.88M
        if ((size_t) tarindex >= targsize)
131
0
          return (-1);
132
2.88M
        target[tarindex] |= (pos - Base64);
133
2.88M
      }
134
2.88M
      tarindex++;
135
2.88M
      state = 0;
136
2.88M
      break;
137
0
    default:
138
0
      abort();
139
11.5M
    }
140
11.5M
  }
141
142
  /*
143
   * We are done decoding Base-64 chars.  Let's see if we ended
144
   * on a byte boundary, and/or with erroneous trailing characters.
145
   */
146
147
15.9k
  if (ch == Pad64) { /* We got a pad char. */
148
10.1k
    ch = next_char (src, end); /* Skip it, get next. */
149
10.1k
    switch (state) {
150
1.27k
    case 0: /* Invalid = in first position */
151
2.48k
    case 1: /* Invalid = in second position */
152
2.48k
      return (-1);
153
154
4.92k
    case 2: /* Valid, means one byte of info */
155
      /* Skip any number of spaces. */
156
5.90k
      for ((void) NULL; ch != '\0'; ch = next_char (src, end))
157
5.00k
        if (!isspace((unsigned char) ch))
158
4.02k
          break;
159
      /* Make sure there is another trailing = sign. */
160
4.92k
      if (ch != Pad64)
161
955
        return (-1);
162
3.96k
      ch = next_char (src, end); /* Skip the = */
163
      /* Fall through to "single trailing =" case. */
164
      /* FALLTHROUGH */
165
166
6.70k
    case 3: /* Valid, means two bytes of info */
167
      /*
168
       * We know this char is an =.  Is there anything but
169
       * whitespace after it?
170
       */
171
7.62k
      for ((void)NULL; src != end; ch = next_char (src, end))
172
1.46k
        if (!isspace((unsigned char) ch))
173
544
          return (-1);
174
175
      /*
176
       * Now make sure for cases 2 and 3 that the "extra"
177
       * bits that slopped past the last full byte were
178
       * zeros.  If we don't check them, they become a
179
       * subliminal channel.
180
       */
181
6.16k
      if (target && target[tarindex] != 0)
182
246
        return (-1);
183
10.1k
    }
184
10.1k
  } else {
185
    /*
186
     * We ended by seeing the end of the string.  Make sure we
187
     * have no partial bytes lying around.
188
     */
189
5.78k
    if (state != 0)
190
1.62k
      return (-1);
191
5.78k
  }
192
193
10.0k
  return (tarindex);
194
15.9k
}
195
196
int
197
p11_b64_ntop (const unsigned char *src,
198
              size_t srclength,
199
              char *target,
200
              size_t targsize,
201
              int breakl)
202
0
{
203
0
  size_t len = 0;
204
0
  unsigned char input[3];
205
0
  unsigned char output[4];
206
0
  size_t i;
207
208
0
  while (srclength > 0) {
209
0
    if (2 < srclength) {
210
0
      input[0] = *src++;
211
0
      input[1] = *src++;
212
0
      input[2] = *src++;
213
0
      srclength -= 3;
214
215
0
      output[0] = input[0] >> 2;
216
0
      output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
217
0
      output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
218
0
      output[3] = input[2] & 0x3f;
219
220
0
    } else {
221
0
      assert (0 != srclength);
222
      /* Get what's left. */
223
0
      input[0] = input[1] = input[2] = '\0';
224
0
      for (i = 0; i < srclength; i++)
225
0
        input[i] = *src++;
226
227
0
      output[0] = input[0] >> 2;
228
0
      output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
229
0
      if (srclength == 1)
230
0
        output[2] = 255;
231
0
      else
232
0
        output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
233
0
      output[3] = 255;
234
235
0
      srclength = 0;
236
0
    }
237
238
0
    for (i = 0; i < 4; i++) {
239
0
      if (breakl && len % (breakl + 1) == 0) {
240
0
        assert (len + 1 < targsize);
241
0
        target[len++] = '\n';
242
0
      }
243
244
0
      assert(output[i] == 255 || output[i] < 64);
245
0
      assert (len + 1 < targsize);
246
247
0
      if (output[i] == 255)
248
0
        target[len++] = Pad64;
249
0
      else
250
0
        target[len++] = Base64[output[i]];
251
0
    }
252
0
  }
253
254
0
  assert (len < targsize);
255
0
  target[len] = '\0';      /* Returned value doesn't count \0. */
256
0
  return len;
257
0
}