xref: /freebsd/contrib/ldns/compat/b64_pton.c (revision 986ba33c7a3bc8f5ba13c7a9d6512602f6e32c61)
17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav  * Copyright (c) 1996, 1998 by Internet Software Consortium.
37b5038d7SDag-Erling Smørgrav  *
47b5038d7SDag-Erling Smørgrav  * Permission to use, copy, modify, and distribute this software for any
57b5038d7SDag-Erling Smørgrav  * purpose with or without fee is hereby granted, provided that the above
67b5038d7SDag-Erling Smørgrav  * copyright notice and this permission notice appear in all copies.
77b5038d7SDag-Erling Smørgrav  *
87b5038d7SDag-Erling Smørgrav  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
97b5038d7SDag-Erling Smørgrav  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
107b5038d7SDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
117b5038d7SDag-Erling Smørgrav  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
127b5038d7SDag-Erling Smørgrav  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
137b5038d7SDag-Erling Smørgrav  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
147b5038d7SDag-Erling Smørgrav  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
157b5038d7SDag-Erling Smørgrav  * SOFTWARE.
167b5038d7SDag-Erling Smørgrav  */
177b5038d7SDag-Erling Smørgrav 
187b5038d7SDag-Erling Smørgrav /*
197b5038d7SDag-Erling Smørgrav  * Portions Copyright (c) 1995 by International Business Machines, Inc.
207b5038d7SDag-Erling Smørgrav  *
217b5038d7SDag-Erling Smørgrav  * International Business Machines, Inc. (hereinafter called IBM) grants
227b5038d7SDag-Erling Smørgrav  * permission under its copyrights to use, copy, modify, and distribute this
237b5038d7SDag-Erling Smørgrav  * Software with or without fee, provided that the above copyright notice and
247b5038d7SDag-Erling Smørgrav  * all paragraphs of this notice appear in all copies, and that the name of IBM
257b5038d7SDag-Erling Smørgrav  * not be used in connection with the marketing of any product incorporating
267b5038d7SDag-Erling Smørgrav  * the Software or modifications thereof, without specific, written prior
277b5038d7SDag-Erling Smørgrav  * permission.
287b5038d7SDag-Erling Smørgrav  *
297b5038d7SDag-Erling Smørgrav  * To the extent it has a right to do so, IBM grants an immunity from suit
307b5038d7SDag-Erling Smørgrav  * under its patents, if any, for the use, sale or manufacture of products to
317b5038d7SDag-Erling Smørgrav  * the extent that such products are used for performing Domain Name System
327b5038d7SDag-Erling Smørgrav  * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
337b5038d7SDag-Erling Smørgrav  * granted for any product per se or for any other function of any product.
347b5038d7SDag-Erling Smørgrav  *
357b5038d7SDag-Erling Smørgrav  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
367b5038d7SDag-Erling Smørgrav  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
377b5038d7SDag-Erling Smørgrav  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
387b5038d7SDag-Erling Smørgrav  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
397b5038d7SDag-Erling Smørgrav  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
407b5038d7SDag-Erling Smørgrav  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
417b5038d7SDag-Erling Smørgrav  */
427b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
437b5038d7SDag-Erling Smørgrav #include <ctype.h>
447b5038d7SDag-Erling Smørgrav #include <stdlib.h>
457b5038d7SDag-Erling Smørgrav #include <string.h>
467b5038d7SDag-Erling Smørgrav 
477b5038d7SDag-Erling Smørgrav static const char Base64[] =
487b5038d7SDag-Erling Smørgrav 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
497b5038d7SDag-Erling Smørgrav static const char Pad64 = '=';
507b5038d7SDag-Erling Smørgrav 
517b5038d7SDag-Erling Smørgrav /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
527b5038d7SDag-Erling Smørgrav    The following encoding technique is taken from RFC 1521 by Borenstein
537b5038d7SDag-Erling Smørgrav    and Freed.  It is reproduced here in a slightly edited form for
547b5038d7SDag-Erling Smørgrav    convenience.
557b5038d7SDag-Erling Smørgrav 
567b5038d7SDag-Erling Smørgrav    A 65-character subset of US-ASCII is used, enabling 6 bits to be
577b5038d7SDag-Erling Smørgrav    represented per printable character. (The extra 65th character, "=",
587b5038d7SDag-Erling Smørgrav    is used to signify a special processing function.)
597b5038d7SDag-Erling Smørgrav 
607b5038d7SDag-Erling Smørgrav    The encoding process represents 24-bit groups of input bits as output
617b5038d7SDag-Erling Smørgrav    strings of 4 encoded characters. Proceeding from left to right, a
627b5038d7SDag-Erling Smørgrav    24-bit input group is formed by concatenating 3 8-bit input groups.
637b5038d7SDag-Erling Smørgrav    These 24 bits are then treated as 4 concatenated 6-bit groups, each
647b5038d7SDag-Erling Smørgrav    of which is translated into a single digit in the base64 alphabet.
657b5038d7SDag-Erling Smørgrav 
667b5038d7SDag-Erling Smørgrav    Each 6-bit group is used as an index into an array of 64 printable
677b5038d7SDag-Erling Smørgrav    characters. The character referenced by the index is placed in the
687b5038d7SDag-Erling Smørgrav    output string.
697b5038d7SDag-Erling Smørgrav 
707b5038d7SDag-Erling Smørgrav                          Table 1: The Base64 Alphabet
717b5038d7SDag-Erling Smørgrav 
727b5038d7SDag-Erling Smørgrav       Value Encoding  Value Encoding  Value Encoding  Value Encoding
737b5038d7SDag-Erling Smørgrav           0 A            17 R            34 i            51 z
747b5038d7SDag-Erling Smørgrav           1 B            18 S            35 j            52 0
757b5038d7SDag-Erling Smørgrav           2 C            19 T            36 k            53 1
767b5038d7SDag-Erling Smørgrav           3 D            20 U            37 l            54 2
777b5038d7SDag-Erling Smørgrav           4 E            21 V            38 m            55 3
787b5038d7SDag-Erling Smørgrav           5 F            22 W            39 n            56 4
797b5038d7SDag-Erling Smørgrav           6 G            23 X            40 o            57 5
807b5038d7SDag-Erling Smørgrav           7 H            24 Y            41 p            58 6
817b5038d7SDag-Erling Smørgrav           8 I            25 Z            42 q            59 7
827b5038d7SDag-Erling Smørgrav           9 J            26 a            43 r            60 8
837b5038d7SDag-Erling Smørgrav          10 K            27 b            44 s            61 9
847b5038d7SDag-Erling Smørgrav          11 L            28 c            45 t            62 +
857b5038d7SDag-Erling Smørgrav          12 M            29 d            46 u            63 /
867b5038d7SDag-Erling Smørgrav          13 N            30 e            47 v
877b5038d7SDag-Erling Smørgrav          14 O            31 f            48 w         (pad) =
887b5038d7SDag-Erling Smørgrav          15 P            32 g            49 x
897b5038d7SDag-Erling Smørgrav          16 Q            33 h            50 y
907b5038d7SDag-Erling Smørgrav 
917b5038d7SDag-Erling Smørgrav    Special processing is performed if fewer than 24 bits are available
927b5038d7SDag-Erling Smørgrav    at the end of the data being encoded.  A full encoding quantum is
937b5038d7SDag-Erling Smørgrav    always completed at the end of a quantity.  When fewer than 24 input
947b5038d7SDag-Erling Smørgrav    bits are available in an input group, zero bits are added (on the
957b5038d7SDag-Erling Smørgrav    right) to form an integral number of 6-bit groups.  Padding at the
967b5038d7SDag-Erling Smørgrav    end of the data is performed using the '=' character.
977b5038d7SDag-Erling Smørgrav 
987b5038d7SDag-Erling Smørgrav    Since all base64 input is an integral number of octets, only the
997b5038d7SDag-Erling Smørgrav          -------------------------------------------------
1007b5038d7SDag-Erling Smørgrav    following cases can arise:
1017b5038d7SDag-Erling Smørgrav 
1027b5038d7SDag-Erling Smørgrav        (1) the final quantum of encoding input is an integral
1037b5038d7SDag-Erling Smørgrav            multiple of 24 bits; here, the final unit of encoded
1047b5038d7SDag-Erling Smørgrav 	   output will be an integral multiple of 4 characters
1057b5038d7SDag-Erling Smørgrav 	   with no "=" padding,
1067b5038d7SDag-Erling Smørgrav        (2) the final quantum of encoding input is exactly 8 bits;
1077b5038d7SDag-Erling Smørgrav            here, the final unit of encoded output will be two
1087b5038d7SDag-Erling Smørgrav 	   characters followed by two "=" padding characters, or
1097b5038d7SDag-Erling Smørgrav        (3) the final quantum of encoding input is exactly 16 bits;
1107b5038d7SDag-Erling Smørgrav            here, the final unit of encoded output will be three
1117b5038d7SDag-Erling Smørgrav 	   characters followed by one "=" padding character.
1127b5038d7SDag-Erling Smørgrav    */
1137b5038d7SDag-Erling Smørgrav 
1147b5038d7SDag-Erling Smørgrav /* skips all whitespace anywhere.
1157b5038d7SDag-Erling Smørgrav    converts characters, four at a time, starting at (or after)
1167b5038d7SDag-Erling Smørgrav    src from base - 64 numbers into three 8 bit bytes in the target area.
1177b5038d7SDag-Erling Smørgrav    it returns the number of data bytes stored at the target, or -1 on error.
1187b5038d7SDag-Erling Smørgrav  */
1197b5038d7SDag-Erling Smørgrav 
1207b5038d7SDag-Erling Smørgrav int
ldns_b64_pton(char const * origsrc,uint8_t * target,size_t targsize)121*986ba33cSDag-Erling Smørgrav ldns_b64_pton(char const *origsrc, uint8_t *target, size_t targsize)
1227b5038d7SDag-Erling Smørgrav {
123*986ba33cSDag-Erling Smørgrav 	unsigned char const* src = (unsigned char*)origsrc;
1247b5038d7SDag-Erling Smørgrav 	int tarindex, state, ch;
1257b5038d7SDag-Erling Smørgrav 	char *pos;
1267b5038d7SDag-Erling Smørgrav 
1277b5038d7SDag-Erling Smørgrav 	state = 0;
1287b5038d7SDag-Erling Smørgrav 	tarindex = 0;
1297b5038d7SDag-Erling Smørgrav 
130*986ba33cSDag-Erling Smørgrav 	if (strlen(origsrc) == 0) {
1317b5038d7SDag-Erling Smørgrav 		return 0;
1327b5038d7SDag-Erling Smørgrav 	}
1337b5038d7SDag-Erling Smørgrav 
1347b5038d7SDag-Erling Smørgrav 	while ((ch = *src++) != '\0') {
1357b5038d7SDag-Erling Smørgrav 		if (isspace((unsigned char)ch))        /* Skip whitespace anywhere. */
1367b5038d7SDag-Erling Smørgrav 			continue;
1377b5038d7SDag-Erling Smørgrav 
1387b5038d7SDag-Erling Smørgrav 		if (ch == Pad64)
1397b5038d7SDag-Erling Smørgrav 			break;
1407b5038d7SDag-Erling Smørgrav 
1417b5038d7SDag-Erling Smørgrav 		pos = strchr(Base64, ch);
1427b5038d7SDag-Erling Smørgrav 		if (pos == 0) {
1437b5038d7SDag-Erling Smørgrav 			/* A non-base64 character. */
1447b5038d7SDag-Erling Smørgrav 			return (-1);
1457b5038d7SDag-Erling Smørgrav 		}
1467b5038d7SDag-Erling Smørgrav 
1477b5038d7SDag-Erling Smørgrav 		switch (state) {
1487b5038d7SDag-Erling Smørgrav 		case 0:
1497b5038d7SDag-Erling Smørgrav 			if (target) {
1507b5038d7SDag-Erling Smørgrav 				if ((size_t)tarindex >= targsize)
1517b5038d7SDag-Erling Smørgrav 					return (-1);
1527b5038d7SDag-Erling Smørgrav 				target[tarindex] = (pos - Base64) << 2;
1537b5038d7SDag-Erling Smørgrav 			}
1547b5038d7SDag-Erling Smørgrav 			state = 1;
1557b5038d7SDag-Erling Smørgrav 			break;
1567b5038d7SDag-Erling Smørgrav 		case 1:
1577b5038d7SDag-Erling Smørgrav 			if (target) {
1587b5038d7SDag-Erling Smørgrav 				if ((size_t)tarindex + 1 >= targsize)
1597b5038d7SDag-Erling Smørgrav 					return (-1);
1607b5038d7SDag-Erling Smørgrav 				target[tarindex]   |=  (pos - Base64) >> 4;
1617b5038d7SDag-Erling Smørgrav 				target[tarindex+1]  = ((pos - Base64) & 0x0f)
1627b5038d7SDag-Erling Smørgrav 							<< 4 ;
1637b5038d7SDag-Erling Smørgrav 			}
1647b5038d7SDag-Erling Smørgrav 			tarindex++;
1657b5038d7SDag-Erling Smørgrav 			state = 2;
1667b5038d7SDag-Erling Smørgrav 			break;
1677b5038d7SDag-Erling Smørgrav 		case 2:
1687b5038d7SDag-Erling Smørgrav 			if (target) {
1697b5038d7SDag-Erling Smørgrav 				if ((size_t)tarindex + 1 >= targsize)
1707b5038d7SDag-Erling Smørgrav 					return (-1);
1717b5038d7SDag-Erling Smørgrav 				target[tarindex]   |=  (pos - Base64) >> 2;
1727b5038d7SDag-Erling Smørgrav 				target[tarindex+1]  = ((pos - Base64) & 0x03)
1737b5038d7SDag-Erling Smørgrav 							<< 6;
1747b5038d7SDag-Erling Smørgrav 			}
1757b5038d7SDag-Erling Smørgrav 			tarindex++;
1767b5038d7SDag-Erling Smørgrav 			state = 3;
1777b5038d7SDag-Erling Smørgrav 			break;
1787b5038d7SDag-Erling Smørgrav 		case 3:
1797b5038d7SDag-Erling Smørgrav 			if (target) {
1807b5038d7SDag-Erling Smørgrav 				if ((size_t)tarindex >= targsize)
1817b5038d7SDag-Erling Smørgrav 					return (-1);
1827b5038d7SDag-Erling Smørgrav 				target[tarindex] |= (pos - Base64);
1837b5038d7SDag-Erling Smørgrav 			}
1847b5038d7SDag-Erling Smørgrav 			tarindex++;
1857b5038d7SDag-Erling Smørgrav 			state = 0;
1867b5038d7SDag-Erling Smørgrav 			break;
1877b5038d7SDag-Erling Smørgrav 		default:
1887b5038d7SDag-Erling Smørgrav 			abort();
1897b5038d7SDag-Erling Smørgrav 		}
1907b5038d7SDag-Erling Smørgrav 	}
1917b5038d7SDag-Erling Smørgrav 
1927b5038d7SDag-Erling Smørgrav 	/*
1937b5038d7SDag-Erling Smørgrav 	 * We are done decoding Base-64 chars.  Let's see if we ended
1947b5038d7SDag-Erling Smørgrav 	 * on a byte boundary, and/or with erroneous trailing characters.
1957b5038d7SDag-Erling Smørgrav 	 */
1967b5038d7SDag-Erling Smørgrav 
1977b5038d7SDag-Erling Smørgrav 	if (ch == Pad64) {		/* We got a pad char. */
1987b5038d7SDag-Erling Smørgrav 		ch = *src++;		/* Skip it, get next. */
1997b5038d7SDag-Erling Smørgrav 		switch (state) {
2007b5038d7SDag-Erling Smørgrav 		case 0:		/* Invalid = in first position */
2017b5038d7SDag-Erling Smørgrav 		case 1:		/* Invalid = in second position */
2027b5038d7SDag-Erling Smørgrav 			return (-1);
2037b5038d7SDag-Erling Smørgrav 
2047b5038d7SDag-Erling Smørgrav 		case 2:		/* Valid, means one byte of info */
2057b5038d7SDag-Erling Smørgrav 			/* Skip any number of spaces. */
2067b5038d7SDag-Erling Smørgrav 			for ((void)NULL; ch != '\0'; ch = *src++)
2077b5038d7SDag-Erling Smørgrav 				if (!isspace((unsigned char)ch))
2087b5038d7SDag-Erling Smørgrav 					break;
2097b5038d7SDag-Erling Smørgrav 			/* Make sure there is another trailing = sign. */
2107b5038d7SDag-Erling Smørgrav 			if (ch != Pad64)
2117b5038d7SDag-Erling Smørgrav 				return (-1);
2127b5038d7SDag-Erling Smørgrav 			ch = *src++;		/* Skip the = */
2137b5038d7SDag-Erling Smørgrav 			/* Fall through to "single trailing =" case. */
2147b5038d7SDag-Erling Smørgrav 			/* FALLTHROUGH */
2157b5038d7SDag-Erling Smørgrav 
2167b5038d7SDag-Erling Smørgrav 		case 3:		/* Valid, means two bytes of info */
2177b5038d7SDag-Erling Smørgrav 			/*
2187b5038d7SDag-Erling Smørgrav 			 * We know this char is an =.  Is there anything but
2197b5038d7SDag-Erling Smørgrav 			 * whitespace after it?
2207b5038d7SDag-Erling Smørgrav 			 */
2217b5038d7SDag-Erling Smørgrav 			for ((void)NULL; ch != '\0'; ch = *src++)
2227b5038d7SDag-Erling Smørgrav 				if (!isspace((unsigned char)ch))
2237b5038d7SDag-Erling Smørgrav 					return (-1);
2247b5038d7SDag-Erling Smørgrav 
2257b5038d7SDag-Erling Smørgrav 			/*
2267b5038d7SDag-Erling Smørgrav 			 * Now make sure for cases 2 and 3 that the "extra"
2277b5038d7SDag-Erling Smørgrav 			 * bits that slopped past the last full byte were
2287b5038d7SDag-Erling Smørgrav 			 * zeros.  If we don't check them, they become a
2297b5038d7SDag-Erling Smørgrav 			 * subliminal channel.
2307b5038d7SDag-Erling Smørgrav 			 */
2317b5038d7SDag-Erling Smørgrav 			if (target && target[tarindex] != 0)
2327b5038d7SDag-Erling Smørgrav 				return (-1);
2337b5038d7SDag-Erling Smørgrav 		}
2347b5038d7SDag-Erling Smørgrav 	} else {
2357b5038d7SDag-Erling Smørgrav 		/*
2367b5038d7SDag-Erling Smørgrav 		 * We ended by seeing the end of the string.  Make sure we
2377b5038d7SDag-Erling Smørgrav 		 * have no partial bytes lying around.
2387b5038d7SDag-Erling Smørgrav 		 */
2397b5038d7SDag-Erling Smørgrav 		if (state != 0)
2407b5038d7SDag-Erling Smørgrav 			return (-1);
2417b5038d7SDag-Erling Smørgrav 	}
2427b5038d7SDag-Erling Smørgrav 
2437b5038d7SDag-Erling Smørgrav 	return (tarindex);
2447b5038d7SDag-Erling Smørgrav }
245