1 /*        $NetBSD: base64.c,v 1.3 2021/08/14 16:14:58 christos Exp $  */
2 
3 /* base64.c -- routines to encode/decode base64 data */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2021 The OpenLDAP Foundation.
8  * Portions Copyright 1998-2003 Kurt D. Zeilenga.
9  * Portions Copyright 1995 IBM Corporation.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 /* Portions Copyright (c) 1996, 1998 by Internet Software Consortium.
21  *
22  * Permission to use, copy, modify, and distribute this software for any
23  * purpose with or without fee is hereby granted, provided that the above
24  * copyright notice and this permission notice appear in all copies.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
27  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
28  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
29  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
30  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
31  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
32  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
33  * SOFTWARE.
34  */
35 /* This work is based upon Base64 routines (developed by IBM) found
36  * Berkeley Internet Name Daemon (BIND) as distributed by ISC.  They
37  * were adapted for inclusion in OpenLDAP Software by Kurt D. Zeilenga.
38  */
39 
40 #include <sys/cdefs.h>
41 __RCSID("$NetBSD: base64.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
42 
43 #include "portable.h"
44 
45 #include <ac/assert.h>
46 #include <ac/stdlib.h>
47 #include <ac/ctype.h>
48 #include <ac/string.h>
49 
50 /* include socket.h to get sys/types.h and/or winsock2.h */
51 #include <ac/socket.h>
52 
53 #include "lutil.h"
54 
55 static const char Base64[] =
56           "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
57 static const char Pad64 = '=';
58 
59 /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
60    The following encoding technique is taken from RFC 1521 by Borenstein
61    and Freed.  It is reproduced here in a slightly edited form for
62    convenience.
63 
64    A 65-character subset of US-ASCII is used, enabling 6 bits to be
65    represented per printable character. (The extra 65th character, "=",
66    is used to signify a special processing function.)
67 
68    The encoding process represents 24-bit groups of input bits as output
69    strings of 4 encoded characters. Proceeding from left to right, a
70    24-bit input group is formed by concatenating 3 8-bit input groups.
71    These 24 bits are then treated as 4 concatenated 6-bit groups, each
72    of which is translated into a single digit in the base64 alphabet.
73 
74    Each 6-bit group is used as an index into an array of 64 printable
75    characters. The character referenced by the index is placed in the
76    output string.
77 
78                          Table 1: The Base64 Alphabet
79 
80       Value Encoding  Value Encoding  Value Encoding  Value Encoding
81           0 A            17 R            34 i            51 z
82           1 B            18 S            35 j            52 0
83           2 C            19 T            36 k            53 1
84           3 D            20 U            37 l            54 2
85           4 E            21 V            38 m            55 3
86           5 F            22 W            39 n            56 4
87           6 G            23 X            40 o            57 5
88           7 H            24 Y            41 p            58 6
89           8 I            25 Z            42 q            59 7
90           9 J            26 a            43 r            60 8
91          10 K            27 b            44 s            61 9
92          11 L            28 c            45 t            62 +
93          12 M            29 d            46 u            63 /
94          13 N            30 e            47 v
95          14 O            31 f            48 w         (pad) =
96          15 P            32 g            49 x
97          16 Q            33 h            50 y
98 
99    Special processing is performed if fewer than 24 bits are available
100    at the end of the data being encoded.  A full encoding quantum is
101    always completed at the end of a quantity.  When fewer than 24 input
102    bits are available in an input group, zero bits are added (on the
103    right) to form an integral number of 6-bit groups.  Padding at the
104    end of the data is performed using the '=' character.
105 
106    Since all base64 input is an integral number of octets, only the
107          -------------------------------------------------
108    following cases can arise:
109 
110        (1) the final quantum of encoding input is an integral
111            multiple of 24 bits; here, the final unit of encoded
112              output will be an integral multiple of 4 characters
113              with no "=" padding,
114        (2) the final quantum of encoding input is exactly 8 bits;
115            here, the final unit of encoded output will be two
116              characters followed by two "=" padding characters, or
117        (3) the final quantum of encoding input is exactly 16 bits;
118            here, the final unit of encoded output will be three
119              characters followed by one "=" padding character.
120    */
121 
122 int
lutil_b64_ntop(u_char const * src,size_t srclength,char * target,size_t targsize)123 lutil_b64_ntop(
124           u_char const *src,
125           size_t srclength,
126           char *target,
127           size_t targsize)
128 {
129           size_t datalength = 0;
130           u_char input[3];
131           u_char output[4];
132           size_t i;
133 
134           while (2 < srclength) {
135                     input[0] = *src++;
136                     input[1] = *src++;
137                     input[2] = *src++;
138                     srclength -= 3;
139 
140                     output[0] = input[0] >> 2;
141                     output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
142                     output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
143                     output[3] = input[2] & 0x3f;
144                     assert(output[0] < 64);
145                     assert(output[1] < 64);
146                     assert(output[2] < 64);
147                     assert(output[3] < 64);
148 
149                     if (datalength + 4 > targsize)
150                               return (-1);
151                     target[datalength++] = Base64[output[0]];
152                     target[datalength++] = Base64[output[1]];
153                     target[datalength++] = Base64[output[2]];
154                     target[datalength++] = Base64[output[3]];
155           }
156 
157           /* Now we worry about padding. */
158           if (0 != srclength) {
159                     /* Get what's left. */
160                     input[0] = input[1] = input[2] = '\0';
161                     for (i = 0; i < srclength; i++)
162                               input[i] = *src++;
163 
164                     output[0] = input[0] >> 2;
165                     output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
166                     output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
167                     assert(output[0] < 64);
168                     assert(output[1] < 64);
169                     assert(output[2] < 64);
170 
171                     if (datalength + 4 > targsize)
172                               return (-1);
173                     target[datalength++] = Base64[output[0]];
174                     target[datalength++] = Base64[output[1]];
175                     if (srclength == 1)
176                               target[datalength++] = Pad64;
177                     else
178                               target[datalength++] = Base64[output[2]];
179                     target[datalength++] = Pad64;
180           }
181           if (datalength >= targsize)
182                     return (-1);
183           target[datalength] = '\0';    /* Returned value doesn't count \0. */
184           return (datalength);
185 }
186 
187 /* skips all whitespace anywhere.
188    converts characters, four at a time, starting at (or after)
189    src from base - 64 numbers into three 8 bit bytes in the target area.
190    it returns the number of data bytes stored at the target, or -1 on error.
191  */
192 
193 int
lutil_b64_pton(char const * src,u_char * target,size_t targsize)194 lutil_b64_pton(
195           char const *src,
196           u_char *target,
197           size_t targsize)
198 {
199           int tarindex, state, ch;
200           char *pos;
201 
202           state = 0;
203           tarindex = 0;
204 
205           while ((ch = *src++) != '\0') {
206                     if (isascii(ch) && isspace(ch))         /* Skip whitespace anywhere. */
207                               continue;
208 
209                     if (ch == Pad64)
210                               break;
211 
212                     pos = strchr(Base64, ch);
213                     if (pos == 0)                 /* A non-base64 character. */
214                               return (-1);
215 
216                     switch (state) {
217                     case 0:
218                               if (target) {
219                                         if ((size_t)tarindex >= targsize)
220                                                   return (-1);
221                                         target[tarindex] = (pos - Base64) << 2;
222                               }
223                               state = 1;
224                               break;
225                     case 1:
226                               if (target) {
227                                         if ((size_t)tarindex + 1 >= targsize)
228                                                   return (-1);
229                                         target[tarindex]   |=  (pos - Base64) >> 4;
230                                         target[tarindex+1]  = ((pos - Base64) & 0x0f)
231                                                                       << 4 ;
232                               }
233                               tarindex++;
234                               state = 2;
235                               break;
236                     case 2:
237                               if (target) {
238                                         if ((size_t)tarindex + 1 >= targsize)
239                                                   return (-1);
240                                         target[tarindex]   |=  (pos - Base64) >> 2;
241                                         target[tarindex+1]  = ((pos - Base64) & 0x03)
242                                                                       << 6;
243                               }
244                               tarindex++;
245                               state = 3;
246                               break;
247                     case 3:
248                               if (target) {
249                                         if ((size_t)tarindex >= targsize)
250                                                   return (-1);
251                                         target[tarindex] |= (pos - Base64);
252                               }
253                               tarindex++;
254                               state = 0;
255                               break;
256                     default:
257                               abort();
258                     }
259           }
260 
261           /*
262            * We are done decoding Base-64 chars.  Let's see if we ended
263            * on a byte boundary, and/or with erroneous trailing characters.
264            */
265 
266           if (ch == Pad64) {            /* We got a pad char. */
267                     ch = *src++;                  /* Skip it, get next. */
268                     switch (state) {
269                     case 0:             /* Invalid = in first position */
270                     case 1:             /* Invalid = in second position */
271                               return (-1);
272 
273                     case 2:             /* Valid, means one byte of info */
274                               /* Skip any number of spaces. */
275                               for ((void)NULL; ch != '\0'; ch = *src++)
276                                         if (! (isascii(ch) && isspace(ch)))
277                                                   break;
278                               /* Make sure there is another trailing = sign. */
279                               if (ch != Pad64)
280                                         return (-1);
281                               ch = *src++;                  /* Skip the = */
282                               /* Fall through to "single trailing =" case. */
283                               /* FALLTHROUGH */
284 
285                     case 3:             /* Valid, means two bytes of info */
286                               /*
287                                * We know this char is an =.  Is there anything but
288                                * whitespace after it?
289                                */
290                               for ((void)NULL; ch != '\0'; ch = *src++)
291                                         if (! (isascii(ch) && isspace(ch)))
292                                                   return (-1);
293 
294                               /*
295                                * Now make sure for cases 2 and 3 that the "extra"
296                                * bits that slopped past the last full byte were
297                                * zeros.  If we don't check them, they become a
298                                * subliminal channel.
299                                */
300                               if (target && target[tarindex] != 0)
301                                         return (-1);
302                     }
303           } else {
304                     /*
305                      * We ended by seeing the end of the string.  Make sure we
306                      * have no partial bytes lying around.
307                      */
308                     if (state != 0)
309                               return (-1);
310           }
311 
312           return (tarindex);
313 }
314