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