xref: /dflybsd-src/contrib/ldns/compat/b64_pton.c (revision 5340022ad92b5f5299ced3631de5d1bf90a7f749)
1825eb42bSJan Lentfer /*
2825eb42bSJan Lentfer  * Copyright (c) 1996, 1998 by Internet Software Consortium.
3825eb42bSJan Lentfer  *
4825eb42bSJan Lentfer  * Permission to use, copy, modify, and distribute this software for any
5825eb42bSJan Lentfer  * purpose with or without fee is hereby granted, provided that the above
6825eb42bSJan Lentfer  * copyright notice and this permission notice appear in all copies.
7825eb42bSJan Lentfer  *
8825eb42bSJan Lentfer  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9825eb42bSJan Lentfer  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10825eb42bSJan Lentfer  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11825eb42bSJan Lentfer  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12825eb42bSJan Lentfer  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13825eb42bSJan Lentfer  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14825eb42bSJan Lentfer  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15825eb42bSJan Lentfer  * SOFTWARE.
16825eb42bSJan Lentfer  */
17825eb42bSJan Lentfer 
18825eb42bSJan Lentfer /*
19825eb42bSJan Lentfer  * Portions Copyright (c) 1995 by International Business Machines, Inc.
20825eb42bSJan Lentfer  *
21825eb42bSJan Lentfer  * International Business Machines, Inc. (hereinafter called IBM) grants
22825eb42bSJan Lentfer  * permission under its copyrights to use, copy, modify, and distribute this
23825eb42bSJan Lentfer  * Software with or without fee, provided that the above copyright notice and
24825eb42bSJan Lentfer  * all paragraphs of this notice appear in all copies, and that the name of IBM
25825eb42bSJan Lentfer  * not be used in connection with the marketing of any product incorporating
26825eb42bSJan Lentfer  * the Software or modifications thereof, without specific, written prior
27825eb42bSJan Lentfer  * permission.
28825eb42bSJan Lentfer  *
29825eb42bSJan Lentfer  * To the extent it has a right to do so, IBM grants an immunity from suit
30825eb42bSJan Lentfer  * under its patents, if any, for the use, sale or manufacture of products to
31825eb42bSJan Lentfer  * the extent that such products are used for performing Domain Name System
32825eb42bSJan Lentfer  * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
33825eb42bSJan Lentfer  * granted for any product per se or for any other function of any product.
34825eb42bSJan Lentfer  *
35825eb42bSJan Lentfer  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
36825eb42bSJan Lentfer  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
37825eb42bSJan Lentfer  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
38825eb42bSJan Lentfer  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
39825eb42bSJan Lentfer  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
40825eb42bSJan Lentfer  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
41825eb42bSJan Lentfer  */
42825eb42bSJan Lentfer #include <ldns/config.h>
43825eb42bSJan Lentfer #include <ctype.h>
44825eb42bSJan Lentfer #include <stdlib.h>
45825eb42bSJan Lentfer #include <string.h>
46825eb42bSJan Lentfer 
47825eb42bSJan Lentfer static const char Base64[] =
48825eb42bSJan Lentfer 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
49825eb42bSJan Lentfer static const char Pad64 = '=';
50825eb42bSJan Lentfer 
51825eb42bSJan Lentfer /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
52825eb42bSJan Lentfer    The following encoding technique is taken from RFC 1521 by Borenstein
53825eb42bSJan Lentfer    and Freed.  It is reproduced here in a slightly edited form for
54825eb42bSJan Lentfer    convenience.
55825eb42bSJan Lentfer 
56825eb42bSJan Lentfer    A 65-character subset of US-ASCII is used, enabling 6 bits to be
57825eb42bSJan Lentfer    represented per printable character. (The extra 65th character, "=",
58825eb42bSJan Lentfer    is used to signify a special processing function.)
59825eb42bSJan Lentfer 
60825eb42bSJan Lentfer    The encoding process represents 24-bit groups of input bits as output
61825eb42bSJan Lentfer    strings of 4 encoded characters. Proceeding from left to right, a
62825eb42bSJan Lentfer    24-bit input group is formed by concatenating 3 8-bit input groups.
63825eb42bSJan Lentfer    These 24 bits are then treated as 4 concatenated 6-bit groups, each
64825eb42bSJan Lentfer    of which is translated into a single digit in the base64 alphabet.
65825eb42bSJan Lentfer 
66825eb42bSJan Lentfer    Each 6-bit group is used as an index into an array of 64 printable
67825eb42bSJan Lentfer    characters. The character referenced by the index is placed in the
68825eb42bSJan Lentfer    output string.
69825eb42bSJan Lentfer 
70825eb42bSJan Lentfer                          Table 1: The Base64 Alphabet
71825eb42bSJan Lentfer 
72825eb42bSJan Lentfer       Value Encoding  Value Encoding  Value Encoding  Value Encoding
73825eb42bSJan Lentfer           0 A            17 R            34 i            51 z
74825eb42bSJan Lentfer           1 B            18 S            35 j            52 0
75825eb42bSJan Lentfer           2 C            19 T            36 k            53 1
76825eb42bSJan Lentfer           3 D            20 U            37 l            54 2
77825eb42bSJan Lentfer           4 E            21 V            38 m            55 3
78825eb42bSJan Lentfer           5 F            22 W            39 n            56 4
79825eb42bSJan Lentfer           6 G            23 X            40 o            57 5
80825eb42bSJan Lentfer           7 H            24 Y            41 p            58 6
81825eb42bSJan Lentfer           8 I            25 Z            42 q            59 7
82825eb42bSJan Lentfer           9 J            26 a            43 r            60 8
83825eb42bSJan Lentfer          10 K            27 b            44 s            61 9
84825eb42bSJan Lentfer          11 L            28 c            45 t            62 +
85825eb42bSJan Lentfer          12 M            29 d            46 u            63 /
86825eb42bSJan Lentfer          13 N            30 e            47 v
87825eb42bSJan Lentfer          14 O            31 f            48 w         (pad) =
88825eb42bSJan Lentfer          15 P            32 g            49 x
89825eb42bSJan Lentfer          16 Q            33 h            50 y
90825eb42bSJan Lentfer 
91825eb42bSJan Lentfer    Special processing is performed if fewer than 24 bits are available
92825eb42bSJan Lentfer    at the end of the data being encoded.  A full encoding quantum is
93825eb42bSJan Lentfer    always completed at the end of a quantity.  When fewer than 24 input
94825eb42bSJan Lentfer    bits are available in an input group, zero bits are added (on the
95825eb42bSJan Lentfer    right) to form an integral number of 6-bit groups.  Padding at the
96825eb42bSJan Lentfer    end of the data is performed using the '=' character.
97825eb42bSJan Lentfer 
98825eb42bSJan Lentfer    Since all base64 input is an integral number of octets, only the
99825eb42bSJan Lentfer          -------------------------------------------------
100825eb42bSJan Lentfer    following cases can arise:
101825eb42bSJan Lentfer 
102825eb42bSJan Lentfer        (1) the final quantum of encoding input is an integral
103825eb42bSJan Lentfer            multiple of 24 bits; here, the final unit of encoded
104825eb42bSJan Lentfer 	   output will be an integral multiple of 4 characters
105825eb42bSJan Lentfer 	   with no "=" padding,
106825eb42bSJan Lentfer        (2) the final quantum of encoding input is exactly 8 bits;
107825eb42bSJan Lentfer            here, the final unit of encoded output will be two
108825eb42bSJan Lentfer 	   characters followed by two "=" padding characters, or
109825eb42bSJan Lentfer        (3) the final quantum of encoding input is exactly 16 bits;
110825eb42bSJan Lentfer            here, the final unit of encoded output will be three
111825eb42bSJan Lentfer 	   characters followed by one "=" padding character.
112825eb42bSJan Lentfer    */
113825eb42bSJan Lentfer 
114825eb42bSJan Lentfer /* skips all whitespace anywhere.
115825eb42bSJan Lentfer    converts characters, four at a time, starting at (or after)
116825eb42bSJan Lentfer    src from base - 64 numbers into three 8 bit bytes in the target area.
117825eb42bSJan Lentfer    it returns the number of data bytes stored at the target, or -1 on error.
118825eb42bSJan Lentfer  */
119825eb42bSJan Lentfer 
120825eb42bSJan Lentfer int
ldns_b64_pton(char const * origsrc,uint8_t * target,size_t targsize)121*5340022aSzrj ldns_b64_pton(char const *origsrc, uint8_t *target, size_t targsize)
122825eb42bSJan Lentfer {
123*5340022aSzrj 	unsigned char const* src = (unsigned char*)origsrc;
124825eb42bSJan Lentfer 	int tarindex, state, ch;
125825eb42bSJan Lentfer 	char *pos;
126825eb42bSJan Lentfer 
127825eb42bSJan Lentfer 	state = 0;
128825eb42bSJan Lentfer 	tarindex = 0;
129825eb42bSJan Lentfer 
130*5340022aSzrj 	if (strlen(origsrc) == 0) {
131825eb42bSJan Lentfer 		return 0;
132825eb42bSJan Lentfer 	}
133825eb42bSJan Lentfer 
134825eb42bSJan Lentfer 	while ((ch = *src++) != '\0') {
135825eb42bSJan Lentfer 		if (isspace((unsigned char)ch))        /* Skip whitespace anywhere. */
136825eb42bSJan Lentfer 			continue;
137825eb42bSJan Lentfer 
138825eb42bSJan Lentfer 		if (ch == Pad64)
139825eb42bSJan Lentfer 			break;
140825eb42bSJan Lentfer 
141825eb42bSJan Lentfer 		pos = strchr(Base64, ch);
142825eb42bSJan Lentfer 		if (pos == 0) {
143825eb42bSJan Lentfer 			/* A non-base64 character. */
144825eb42bSJan Lentfer 			return (-1);
145825eb42bSJan Lentfer 		}
146825eb42bSJan Lentfer 
147825eb42bSJan Lentfer 		switch (state) {
148825eb42bSJan Lentfer 		case 0:
149825eb42bSJan Lentfer 			if (target) {
150825eb42bSJan Lentfer 				if ((size_t)tarindex >= targsize)
151825eb42bSJan Lentfer 					return (-1);
152825eb42bSJan Lentfer 				target[tarindex] = (pos - Base64) << 2;
153825eb42bSJan Lentfer 			}
154825eb42bSJan Lentfer 			state = 1;
155825eb42bSJan Lentfer 			break;
156825eb42bSJan Lentfer 		case 1:
157825eb42bSJan Lentfer 			if (target) {
158825eb42bSJan Lentfer 				if ((size_t)tarindex + 1 >= targsize)
159825eb42bSJan Lentfer 					return (-1);
160825eb42bSJan Lentfer 				target[tarindex]   |=  (pos - Base64) >> 4;
161825eb42bSJan Lentfer 				target[tarindex+1]  = ((pos - Base64) & 0x0f)
162825eb42bSJan Lentfer 							<< 4 ;
163825eb42bSJan Lentfer 			}
164825eb42bSJan Lentfer 			tarindex++;
165825eb42bSJan Lentfer 			state = 2;
166825eb42bSJan Lentfer 			break;
167825eb42bSJan Lentfer 		case 2:
168825eb42bSJan Lentfer 			if (target) {
169825eb42bSJan Lentfer 				if ((size_t)tarindex + 1 >= targsize)
170825eb42bSJan Lentfer 					return (-1);
171825eb42bSJan Lentfer 				target[tarindex]   |=  (pos - Base64) >> 2;
172825eb42bSJan Lentfer 				target[tarindex+1]  = ((pos - Base64) & 0x03)
173825eb42bSJan Lentfer 							<< 6;
174825eb42bSJan Lentfer 			}
175825eb42bSJan Lentfer 			tarindex++;
176825eb42bSJan Lentfer 			state = 3;
177825eb42bSJan Lentfer 			break;
178825eb42bSJan Lentfer 		case 3:
179825eb42bSJan Lentfer 			if (target) {
180825eb42bSJan Lentfer 				if ((size_t)tarindex >= targsize)
181825eb42bSJan Lentfer 					return (-1);
182825eb42bSJan Lentfer 				target[tarindex] |= (pos - Base64);
183825eb42bSJan Lentfer 			}
184825eb42bSJan Lentfer 			tarindex++;
185825eb42bSJan Lentfer 			state = 0;
186825eb42bSJan Lentfer 			break;
187825eb42bSJan Lentfer 		default:
188825eb42bSJan Lentfer 			abort();
189825eb42bSJan Lentfer 		}
190825eb42bSJan Lentfer 	}
191825eb42bSJan Lentfer 
192825eb42bSJan Lentfer 	/*
193825eb42bSJan Lentfer 	 * We are done decoding Base-64 chars.  Let's see if we ended
194825eb42bSJan Lentfer 	 * on a byte boundary, and/or with erroneous trailing characters.
195825eb42bSJan Lentfer 	 */
196825eb42bSJan Lentfer 
197825eb42bSJan Lentfer 	if (ch == Pad64) {		/* We got a pad char. */
198825eb42bSJan Lentfer 		ch = *src++;		/* Skip it, get next. */
199825eb42bSJan Lentfer 		switch (state) {
200825eb42bSJan Lentfer 		case 0:		/* Invalid = in first position */
201825eb42bSJan Lentfer 		case 1:		/* Invalid = in second position */
202825eb42bSJan Lentfer 			return (-1);
203825eb42bSJan Lentfer 
204825eb42bSJan Lentfer 		case 2:		/* Valid, means one byte of info */
205825eb42bSJan Lentfer 			/* Skip any number of spaces. */
206825eb42bSJan Lentfer 			for ((void)NULL; ch != '\0'; ch = *src++)
207825eb42bSJan Lentfer 				if (!isspace((unsigned char)ch))
208825eb42bSJan Lentfer 					break;
209825eb42bSJan Lentfer 			/* Make sure there is another trailing = sign. */
210825eb42bSJan Lentfer 			if (ch != Pad64)
211825eb42bSJan Lentfer 				return (-1);
212825eb42bSJan Lentfer 			ch = *src++;		/* Skip the = */
213825eb42bSJan Lentfer 			/* Fall through to "single trailing =" case. */
214825eb42bSJan Lentfer 			/* FALLTHROUGH */
215825eb42bSJan Lentfer 
216825eb42bSJan Lentfer 		case 3:		/* Valid, means two bytes of info */
217825eb42bSJan Lentfer 			/*
218825eb42bSJan Lentfer 			 * We know this char is an =.  Is there anything but
219825eb42bSJan Lentfer 			 * whitespace after it?
220825eb42bSJan Lentfer 			 */
221825eb42bSJan Lentfer 			for ((void)NULL; ch != '\0'; ch = *src++)
222825eb42bSJan Lentfer 				if (!isspace((unsigned char)ch))
223825eb42bSJan Lentfer 					return (-1);
224825eb42bSJan Lentfer 
225825eb42bSJan Lentfer 			/*
226825eb42bSJan Lentfer 			 * Now make sure for cases 2 and 3 that the "extra"
227825eb42bSJan Lentfer 			 * bits that slopped past the last full byte were
228825eb42bSJan Lentfer 			 * zeros.  If we don't check them, they become a
229825eb42bSJan Lentfer 			 * subliminal channel.
230825eb42bSJan Lentfer 			 */
231825eb42bSJan Lentfer 			if (target && target[tarindex] != 0)
232825eb42bSJan Lentfer 				return (-1);
233825eb42bSJan Lentfer 		}
234825eb42bSJan Lentfer 	} else {
235825eb42bSJan Lentfer 		/*
236825eb42bSJan Lentfer 		 * We ended by seeing the end of the string.  Make sure we
237825eb42bSJan Lentfer 		 * have no partial bytes lying around.
238825eb42bSJan Lentfer 		 */
239825eb42bSJan Lentfer 		if (state != 0)
240825eb42bSJan Lentfer 			return (-1);
241825eb42bSJan Lentfer 	}
242825eb42bSJan Lentfer 
243825eb42bSJan Lentfer 	return (tarindex);
244825eb42bSJan Lentfer }
245