1 /*        $NetBSD: base64.c,v 1.17 2024/01/20 14:52:48 christos Exp $ */
2 
3 /*
4  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (c) 1996-1999 by Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  * Portions Copyright (c) 1995 by International Business Machines, Inc.
22  *
23  * International Business Machines, Inc. (hereinafter called IBM) grants
24  * permission under its copyrights to use, copy, modify, and distribute this
25  * Software with or without fee, provided that the above copyright notice and
26  * all paragraphs of this notice appear in all copies, and that the name of IBM
27  * not be used in connection with the marketing of any product incorporating
28  * the Software or modifications thereof, without specific, written prior
29  * permission.
30  *
31  * To the extent it has a right to do so, IBM grants an immunity from suit
32  * under its patents, if any, for the use, sale or manufacture of products to
33  * the extent that such products are used for performing Domain Name System
34  * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
35  * granted for any product per se or for any other function of any product.
36  *
37  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
38  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
39  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
40  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
41  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
42  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
43  */
44 
45 #include <sys/cdefs.h>
46 #if defined(LIBC_SCCS) && !defined(lint)
47 #if 0
48 static const char rcsid[] = "Id: base64.c,v 1.4 2005/04/27 04:56:34 sra Exp";
49 #else
50 __RCSID("$NetBSD: base64.c,v 1.17 2024/01/20 14:52:48 christos Exp $");
51 #endif
52 #endif /* LIBC_SCCS and not lint */
53 
54 #include "port_before.h"
55 
56 #include <sys/types.h>
57 #include <sys/param.h>
58 #include <sys/socket.h>
59 
60 #include <netinet/in.h>
61 #include <arpa/inet.h>
62 #include <arpa/nameser.h>
63 
64 #include <assert.h>
65 #include <ctype.h>
66 #include <resolv.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 
71 #include "port_after.h"
72 
73 #define Assert(Cond) if (!(Cond)) abort()
74 
75 static const char Base64[] =
76           "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
77 static const char Pad64 = '=';
78 
79 /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
80    The following encoding technique is taken from RFC1521 by Borenstein
81    and Freed.  It is reproduced here in a slightly edited form for
82    convenience.
83 
84    A 65-character subset of US-ASCII is used, enabling 6 bits to be
85    represented per printable character. (The extra 65th character, "=",
86    is used to signify a special processing function.)
87 
88    The encoding process represents 24-bit groups of input bits as output
89    strings of 4 encoded characters. Proceeding from left to right, a
90    24-bit input group is formed by concatenating 3 8-bit input groups.
91    These 24 bits are then treated as 4 concatenated 6-bit groups, each
92    of which is translated into a single digit in the base64 alphabet.
93 
94    Each 6-bit group is used as an index into an array of 64 printable
95    characters. The character referenced by the index is placed in the
96    output string.
97 
98                          Table 1: The Base64 Alphabet
99 
100       Value Encoding  Value Encoding  Value Encoding  Value Encoding
101           0 A            17 R            34 i            51 z
102           1 B            18 S            35 j            52 0
103           2 C            19 T            36 k            53 1
104           3 D            20 U            37 l            54 2
105           4 E            21 V            38 m            55 3
106           5 F            22 W            39 n            56 4
107           6 G            23 X            40 o            57 5
108           7 H            24 Y            41 p            58 6
109           8 I            25 Z            42 q            59 7
110           9 J            26 a            43 r            60 8
111          10 K            27 b            44 s            61 9
112          11 L            28 c            45 t            62 +
113          12 M            29 d            46 u            63 /
114          13 N            30 e            47 v
115          14 O            31 f            48 w         (pad) =
116          15 P            32 g            49 x
117          16 Q            33 h            50 y
118 
119    Special processing is performed if fewer than 24 bits are available
120    at the end of the data being encoded.  A full encoding quantum is
121    always completed at the end of a quantity.  When fewer than 24 input
122    bits are available in an input group, zero bits are added (on the
123    right) to form an integral number of 6-bit groups.  Padding at the
124    end of the data is performed using the '=' character.
125 
126    Since all base64 input is an integral number of octets, only the
127          -------------------------------------------------
128    following cases can arise:
129 
130        (1) the final quantum of encoding input is an integral
131            multiple of 24 bits; here, the final unit of encoded
132              output will be an integral multiple of 4 characters
133              with no "=" padding,
134        (2) the final quantum of encoding input is exactly 8 bits;
135            here, the final unit of encoded output will be two
136              characters followed by two "=" padding characters, or
137        (3) the final quantum of encoding input is exactly 16 bits;
138            here, the final unit of encoded output will be three
139              characters followed by one "=" padding character.
140    */
141 
142 int
b64_ntop(u_char const * src,size_t srclength,char * target,size_t targsize)143 b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
144           size_t datalength = 0;
145           u_char input[3];
146           u_char output[4];
147           size_t i;
148 
149           _DIAGASSERT(src != NULL);
150           _DIAGASSERT(target != NULL);
151 
152           while (2U < srclength) {
153                     input[0] = *src++;
154                     input[1] = *src++;
155                     input[2] = *src++;
156                     srclength -= 3;
157 
158                     output[0] = (uint32_t)input[0] >> 2;
159                     output[1] = ((uint32_t)(input[0] & 0x03) << 4) +
160                         ((uint32_t)input[1] >> 4);
161                     output[2] = ((uint32_t)(input[1] & 0x0f) << 2) +
162                         ((uint32_t)input[2] >> 6);
163                     output[3] = input[2] & 0x3f;
164                     Assert(output[0] < 64);
165                     Assert(output[1] < 64);
166                     Assert(output[2] < 64);
167                     Assert(output[3] < 64);
168 
169                     if (datalength + 4 > targsize)
170                               return -1;
171                     target[datalength++] = Base64[output[0]];
172                     target[datalength++] = Base64[output[1]];
173                     target[datalength++] = Base64[output[2]];
174                     target[datalength++] = Base64[output[3]];
175           }
176 
177           /* Now we worry about padding. */
178           if (0U != srclength) {
179                     /* Get what's left. */
180                     input[0] = input[1] = input[2] = '\0';
181                     for (i = 0; i < srclength; i++)
182                               input[i] = *src++;
183 
184                     output[0] = (uint32_t)input[0] >> 2;
185                     output[1] = ((uint32_t)(input[0] & 0x03) << 4) +
186                         ((uint32_t)input[1] >> 4);
187                     output[2] = ((uint32_t)(input[1] & 0x0f) << 2) +
188                         ((uint32_t)input[2] >> 6);
189                     Assert(output[0] < 64);
190                     Assert(output[1] < 64);
191                     Assert(output[2] < 64);
192 
193                     if (datalength + 4 > targsize)
194                               return -1;
195                     target[datalength++] = Base64[output[0]];
196                     target[datalength++] = Base64[output[1]];
197                     if (srclength == 1U)
198                               target[datalength++] = Pad64;
199                     else
200                               target[datalength++] = Base64[output[2]];
201                     target[datalength++] = Pad64;
202           }
203           if (datalength >= targsize)
204                     return -1;
205           target[datalength] = '\0';    /*%< Returned value doesn't count \\0. */
206           _DIAGASSERT(__type_fit(int, datalength));
207           return (int)datalength;
208 }
209 
210 /* skips all whitespace anywhere.
211    converts characters, four at a time, starting at (or after)
212    src from base - 64 numbers into three 8 bit bytes in the target area.
213    it returns the number of data bytes stored at the target, or -1 on error.
214  */
215 
216 int
b64_pton(char const * src,u_char * target,size_t targsize)217 b64_pton(char const *src, u_char *target, size_t targsize)
218 {
219           size_t tarindex;
220           int state, ch;
221           u_char nextbyte;
222           const char *pos;
223 
224           _DIAGASSERT(src != NULL);
225           _DIAGASSERT(target != NULL);
226 
227           state = 0;
228           tarindex = 0;
229 
230           while ((ch = (u_char) *src++) != '\0') {
231                     if (isspace(ch))    /*%< Skip whitespace anywhere. */
232                               continue;
233 
234                     if (ch == Pad64)
235                               break;
236 
237                     pos = strchr(Base64, ch);
238                     if (pos == NULL)    /*%< A non-base64 character. */
239                               return -1;
240 
241                     switch (state) {
242                     case 0:
243                               if (target) {
244                                         if (tarindex >= targsize)
245                                                   return -1;
246                                         target[tarindex] = (u_char)(pos - Base64) << 2;
247                               }
248                               state = 1;
249                               break;
250                     case 1:
251                               if (target) {
252                                         if (tarindex >= targsize)
253                                                   return -1;
254                                         target[tarindex] |=
255                                             (uint32_t)(pos - Base64) >> 4;
256                                         nextbyte = (u_char)((pos - Base64) & 0x0f) << 4;
257                                         if (tarindex + 1 < targsize)
258                                                   target[tarindex + 1] = nextbyte;
259                                         else if (nextbyte)
260                                                   return -1;
261                               }
262                               tarindex++;
263                               state = 2;
264                               break;
265                     case 2:
266                               if (target) {
267                                         if (tarindex >= targsize)
268                                                   return -1;
269                                         target[tarindex] |=
270                                                   (uint32_t)(pos - Base64) >> 2;
271                                         nextbyte = (u_char)((pos - Base64) & 0x03) << 6;
272                                         if (tarindex + 1 < targsize)
273                                                   target[tarindex + 1] = nextbyte;
274                                         else if (nextbyte)
275                                                   return -1;
276                               }
277                               tarindex++;
278                               state = 3;
279                               break;
280                     case 3:
281                               if (target) {
282                                         if ((size_t)tarindex >= targsize)
283                                                   return -1;
284                                         target[tarindex] |= (u_char)(pos - Base64);
285                               }
286                               tarindex++;
287                               state = 0;
288                               break;
289                     default:
290                               abort();
291                     }
292           }
293 
294           /*
295            * We are done decoding Base-64 chars.  Let's see if we ended
296            * on a byte boundary, and/or with erroneous trailing characters.
297            */
298 
299           if (ch == Pad64) {            /*%< We got a pad char. */
300                     ch = *src++;                  /*%< Skip it, get next. */
301                     switch (state) {
302                     case 0:             /*%< Invalid = in first position */
303                     case 1:             /*%< Invalid = in second position */
304                               return -1;
305 
306                     case 2:             /*%< Valid, means one byte of info */
307                               /* Skip any number of spaces. */
308                               for (; ch != '\0'; ch = (u_char) *src++)
309                                         if (!isspace(ch))
310                                                   break;
311                               /* Make sure there is another trailing = sign. */
312                               if (ch != Pad64)
313                                         return -1;
314                               ch = *src++;                  /*%< Skip the = */
315                               /* Fall through to "single trailing =" case. */
316                               /* FALLTHROUGH */
317 
318                     case 3:             /*%< Valid, means two bytes of info */
319                               /*
320                                * We know this char is an =.  Is there anything but
321                                * whitespace after it?
322                                */
323                               for (; ch != '\0'; ch = (u_char) *src++)
324                                         if (!isspace(ch))
325                                                   return -1;
326 
327                               /*
328                                * Now make sure for cases 2 and 3 that the "extra"
329                                * bits that slopped past the last full byte were
330                                * zeros.  If we don't check them, they become a
331                                * subliminal channel.
332                                */
333                               if (target && tarindex < targsize &&
334                                   target[tarindex] != 0)
335                                         return -1;
336                     }
337           } else {
338                     /*
339                      * We ended by seeing the end of the string.  Make sure we
340                      * have no partial bytes lying around.
341                      */
342                     if (state != 0)
343                               return -1;
344           }
345 
346           _DIAGASSERT(__type_fit(int, tarindex));
347           return (int)tarindex;
348 }
349 
350 /*! \file */
351