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